Html Angular JS 缩放和性能
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17656397/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Angular JS Scaling & Performance
提问by trevorewen
We are pounding our heads against performance issues with an Angular app we are building for a bank.
我们正在用我们为银行构建的 Angular 应用程序来解决性能问题。
Unfortunately, it is a breach of contract to show snippets of the code. Regardless, I can describe some of the main issues going on, and I am hoping that best practice can be recommended.
不幸的是,显示代码片段是违反合同的。无论如何,我可以描述一些正在发生的主要问题,我希望可以推荐最佳实践。
Applications Structure:
应用结构:
- Essentially, a giant multi-form page.
- Each form is its own partial, with nested controllers and partials about 3 levels deep.
- The same forms are ng-repeated over a collection of json objects.
- Each form is bound to the object / model that it is repeated over.
- We are supposed to support anywhere from 1-200 forms on the page.
- 本质上,一个巨大的多形式页面。
- 每个表单都是它自己的部分,具有嵌套的控制器和大约 3 层深的部分。
- 相同的形式在一组 json 对象上重复 ng。
- 每个表单都绑定到它重复的对象/模型。
- 我们应该支持页面上 1-200 个表单。
If you take a look at the timeline. We are spending a great deal of time in the jQuery parse html method, jQuery recalculate stye method, the GC Event (Garbage Collection). I imagine minimizing these should speed things up a bit. They are all a part of the Angular lifecycle, but there may be better ways to avoid them. Here are some screenshots of the profiler:
如果你看一下时间线。我们在 jQuery 解析 html 方法、jQuery 重新计算 stye 方法、GC 事件(垃圾收集)上花费了大量时间。我想尽量减少这些应该会加快速度。它们都是 Angular 生命周期的一部分,但可能有更好的方法来避免它们。以下是分析器的一些屏幕截图:
Ultimately, the app is sluggish as the number of repeated forms goes above 5. Each form is relatively unrelated to the others. We have tried not to watch any shared properties between the forms.
最终,由于重复表单的数量超过 5 个,应用程序变得缓慢。每个表单与其他表单相对无关。我们尝试不查看表单之间的任何共享属性。
回答by btm1
You need to create custom directives in order to curb the performance issues with angular. Unlike ember angular comes with all the bells and whistles turned on and it's up to you to tone it down. Here are a few directives I've created to help you out. Not all data in your app needs to be two way data bound and as a result you can save valuable cpu power by forgoing watch expressions in the page where needed. All of these directives bind data one time and leave it alone.
您需要创建自定义指令以遏制 angular 的性能问题。与 ember angular 不同的是,所有的花里胡哨都打开了,由你来调低它。下面是我创建的一些指令来帮助你。并非应用程序中的所有数据都需要双向数据绑定,因此您可以通过在需要时放弃页面中的 watch 表达式来节省宝贵的 CPU 能力。所有这些指令都会一次性绑定数据,然后不理会它。
https://gist.github.com/btm1/6802599
https://gist.github.com/btm1/6802599
https://gist.github.com/btm1/6802312
https://gist.github.com/btm1/6802312
https://gist.github.com/btm1/6746150
https://gist.github.com/btm1/6746150
One of the answers above talks about ng-repeat having huge performance hits so I give you "set-repeat" a one time data binding repeat directive :)
上面的答案之一谈到 ng-repeat 具有巨大的性能影响,所以我给你“设置重复”一个一次性数据绑定重复指令:)
回答by jssebastian
It is hard to provide a solution without more information about your problem, but I recently experienced (and solved) a performance issuethat may be similar to what you saw, and was unrelated to the $digest cycle.
如果没有关于您的问题的更多信息,很难提供解决方案,但我最近遇到(并解决了)一个性能问题,该问题可能与您所看到的类似,并且与 $digest 循环无关。
Most discussion of angularjs performance you will find (including the excellent post from Misko) is about the performance of dirty checking and the $digest cycle. But that is not the only performance issue you can experience with angularjs. The first step should be to determine if the digest cycle is your problem or not. For this, you can use batarang, or just look at your app and at when precisely it is sluggish. When the digest cycle is slow, essentially any interaction with the UI will be slow.
你会发现大多数关于 angularjs 性能的讨论(包括来自 Misko的优秀帖子)都是关于脏检查和 $digest 循环的性能。但这并不是您在使用 angularjs 时遇到的唯一性能问题。第一步应该是确定摘要周期是否是您的问题。为此,您可以使用 batarang,或者只是查看您的应用程序,看看它何时出现缓慢。当摘要周期很慢时,基本上任何与 UI 的交互都会很慢。
OTOH, you can have an app with a fast digest cycle, that is slow only when loading, switching views, or otherwise changing the sets of components to display, and this can manifest in profiling as a lot of time spent in parsing HTML and garbage collecting. In my case this was solved by doing some pre-computation of the html template to display, instead of relying on ng-repeat, ng-switch, ng-if everywhere.
OTOH,您可以拥有一个具有快速消化周期的应用程序,只有在加载、切换视图或以其他方式更改要显示的组件集时才会缓慢,这可以在分析中体现为大量时间花在解析 HTML 和垃圾上收集。在我的情况下,这是通过对要显示的 html 模板进行一些预计算来解决的,而不是依赖于 ng-repeat、ng-switch、ng-if 无处不在。
I was using an ng-repeat="widget in widgets" containing an ng-switch on the type of widget, to display an arbitrary set of widgets (custom self-contained directives). Replacing this with code to generate the angular template for the specific set of widgets sped up route switching from ~10s to practically instant.
我正在使用一个 ng-repeat="widget in widgets" 包含一个关于小部件类型的 ng-switch,来显示一组任意的小部件(自定义自包含指令)。将其替换为代码以生成特定小部件集的角度模板,可将路由切换从大约 10 秒加速到几乎是即时的。
You can see the google groups thread above for a little more info on how I solved my particular problem, or provide more information about your application if you want some specific suggestions.
您可以查看上面的 google 群组线程,了解有关我如何解决特定问题的更多信息,或者如果您需要一些具体建议,请提供有关您的应用程序的更多信息。
回答by Abbasi
To improve performance in production read very nice one-liner below:
为了提高生产性能,请阅读下面非常好的单行:
Quoting AngularJS Documentation:
引用 AngularJS 文档:
By default AngularJS attaches information about binding and scopes to DOM nodes, and adds CSS classes to data-bound elements:
默认情况下,AngularJS 将有关绑定和作用域的信息附加到 DOM 节点,并将 CSS 类添加到数据绑定元素:
As a result of ngBind, ngBindHtml or {{...}} interpolations, binding data and CSS class ng-binding are attached to the corresponding element.
作为 ngBind、ngBindHtml 或 {{...}} 插值的结果,绑定数据和 CSS 类 ng-binding 被附加到相应的元素。
Where the compiler has created a new scope, the scope and either ng-scope or ng-isolated-scope CSS class are attached to the corresponding element. These scope references can then be accessed via element.scope() and element.isolateScope().
当编译器创建了一个新的作用域时,作用域和 ng-scope 或 ng-isolated-scope CSS 类都附加到相应的元素上。然后可以通过 element.scope() 和 element.isolateScope() 访问这些范围引用。
Tools like Protractor and Batarang need this information to run, but you can disable this in production for a significant performance boost with:
像 Protractor 和 Batarang 这样的工具需要这些信息才能运行,但您可以在生产中禁用它以显着提高性能:
myApp.config(['$compileProvider', function ($compileProvider) {
$compileProvider.debugInfoEnabled(false);
}]);
You can read more details here
您可以在此处阅读更多详细信息
回答by MW.
Generally, AngularJS will perform poorly if there are more than 2000 data-bindings active, i.e. 2000 items in the scope that are being dirty-checked each $digest-cycle. Ng-repeat has a big performance impact because of this; each repeated items sets up at least two bindings, not counting any additional data or directives that are used inside the item.
通常,如果有超过 2000 个数据绑定处于活动状态,即每个 $digest-cycle 范围内有 2000 个项目被脏检查,AngularJS 的性能会很差。因此,Ng-repeat 对性能有很大的影响;每个重复的项目至少设置两个绑定,不计算项目内部使用的任何额外数据或指令。
One of the developers behind AngularJS gives an excellent description of the details of dirty-checking, and its performance in this SO answer:
AngularJS 背后的一位开发人员很好地描述了脏检查的细节,以及它在这个 SO 答案中的表现:
https://stackoverflow.com/a/9693933/179024
https://stackoverflow.com/a/9693933/179024
The comment thread below that answer is worth a read, and I also share some thoughts about it in an answer further down on the same page:
该答案下方的评论线程值得一读,我还在同一页面下方的答案中分享了一些关于它的想法:
回答by 5122014009
Am sorry for putting it as an 'answer' because i do not have enough points yet to make a comment.
很抱歉将其作为“答案”,因为我还没有足够的分数来发表评论。
We have run into similar issues with our AngularJS app. Using 'batarang' it seems having to deal with a large number of scope objects and their relevant $watch expressions creates a performance hiccup. This has set us wondering if another framework or something like ReactJS should be used instead to take care of the 'view' part.
我们的 AngularJS 应用程序也遇到了类似的问题。使用 'batarang' 似乎必须处理大量范围对象,并且它们相关的 $watch 表达式会造成性能问题。这让我们想知道是否应该使用另一个框架或 ReactJS 之类的东西来处理“视图”部分。
回答by Rishul Matta
try avoiding the following
尽量避免以下情况
- please avoid using ng-repeat if you have more than 50 elements in the list at a time and avoid manual watches
do not use ng-click, ng-mouseenter,ng-mouseleave etc mouse events blindly till it is a dire need , try to reduce their numbers by using $event object along with event propagation concepts of js
where ever possible use scope.$digest instead of scope.$watch, this ensures that digest cycle is executed only on the child scopes
- try having nested scopes i.e. one or two controllers inside one parent controller and keep the reusable logic in parent , i used this in nested states while using Ui-router (to fulfill a req where change of URL was required without page refresh ).
most important! REMOVE ALL FILTERS FROM HTML!
- 如果列表中的元素一次超过 50 个,请避免使用 ng-repeat 并避免手动手表
不要盲目使用 ng-click、ng-mouseenter、ng-mouseleave 等鼠标事件,直到迫切需要,尝试通过使用 $event 对象以及 js 的事件传播概念来减少它们的数量
尽可能使用 scope.$digest 而不是 scope.$watch,这确保摘要循环仅在子作用域上执行
- 尝试使用嵌套范围,即在一个父控制器中包含一个或两个控制器,并将可重用逻辑保留在父控制器中,我在使用 Ui-router 时在嵌套状态中使用了它(以满足需要更改 URL 而不刷新页面的请求)。
最重要的!从 HTML 中删除所有过滤器!
all the above trigger a digest cycle on all the scopes of your application so there is a high probability that even when the view has been rendered angular is again executing relentless digest loops
以上所有内容都会在应用程序的所有范围内触发摘要循环,因此很有可能即使视图已呈现 angular 再次执行无情的摘要循环
回答by user239558
A middle ground between moving the DOM manipulation into custom directives and the $watch problems with lots of $watches is to use "bind-once" semantics.
将 DOM 操作移动到自定义指令与大量 $watches 的 $watch 问题之间的中间立场是使用“绑定一次”语义。
This is great for data that is immutable once the data is made available. See bindonce
这对于数据可用后不可变的数据非常有用。见绑定
回答by Zoneh
This will only be a link! This is just an idea I had when I was reading this, I haven't explored this yet but someone probabbly did so I'm waiting for their reply on my idea. How about using shared web workers to get lots of heavy processing out of the ui thread? https://github.com/h2non/sharedworkers-angular-poc
这将只是一个链接!这只是我在阅读本文时的一个想法,我还没有探索过这个,但可能有人这样做了,所以我正在等待他们对我的想法的答复。如何使用共享的 Web Worker 从 ui 线程中获得大量繁重的处理?https://github.com/h2non/sharedworkers-angular-poc
The other idea I had was a simpler one. Would your app benefit from infinite scrolling? I mean these forms probabbly dont all fit on the screen, they are not connected to eachother so why not draw them as they are needed? Load them up in memory then draw them accordingly.
我的另一个想法是一个更简单的想法。您的应用程序会从无限滚动中受益吗?我的意思是这些表格可能并不都适合屏幕,它们没有相互连接,所以为什么不根据需要绘制它们呢?将它们加载到内存中,然后相应地绘制它们。
回答by gleb bahmutov
Just like in any other performance optimization, it is important to know how to profile the application to find the true bottleneck. Then you can solve them one by one. I usually fight the bottlenecks in the following order:
就像在任何其他性能优化中一样,了解如何分析应用程序以找到真正的瓶颈很重要。然后就可以一一解决了。我通常按以下顺序解决瓶颈:
- my javascript code
- angular expressions (complex watchers and filters) that run on each idle digest cycle
- angular constructs (ng-repeat, copying objects for digest cycle)
- 我的 JavaScript 代码
- 在每个空闲摘要循环上运行的角度表达式(复杂的观察器和过滤器)
- 角度构造(ng-repeat,复制摘要循环的对象)
I have profiled an angular example step by step showing how to identify a bottleneck at each step. http://bahmutov.calepin.co/improving-angular-web-app-performance-example.html
我已经逐步分析了一个角度示例,展示了如何在每一步识别瓶颈。http://bahmutov.calepin.co/improving-angular-web-app-performance-example.html