Angular JS Scaling&Performance

我们正在用我们正在为银行build立的一个Angular应用程序来解决性能问题。

不幸的是,显示代码片段是违反合同的。 无论如何,我可以描述一些正在进行的主要问题,我希望可以推荐最佳做法。

应用结构:

  • 本质上,一个巨大的多表格页面。
  • 每种forms都是自己的部分,嵌套的控制器和局部约3层深。
  • 在json对象的集合上重复相同的forms。
  • 每个表单都绑定到重复的对象/模型。
  • 我们应该支持页面上1-200个表单的任何地方。

如果你看看时间表。 我们花费了大量的时间在jQueryparsinghtml方法,jQuery重新计算stye方法,GC事件(垃圾收集)。 我想尽量减less这些应该加快一点点。 它们都是Angular生命周期的一部分,但是可能有更好的方法来避免它们。 这里是剖析器的一些截图:

重新计算样式GC事件

最终,应用程序是缓慢的,因为重复forms的数量超过了5个。每个forms与其他forms是相对无关的。 我们已经尽量不要在表单之间观看任何共享属性。

您需要创build自定义指令来遏制angular度的性能问题。 与余烬不同,随着所有的钟声和口哨打开,它取决于你的口气。 以下是我创build的一些帮助你的指令。 并非您的应用程序中的所有数据都需要双向数据绑定,因此您可以通过在需要的页面中放置监视expression式来节省宝贵的CPU功耗。 所有这些指令都将数据绑定一次,并保持独立。

https://gist.github.com/btm1/6802599

https://gist.github.com/btm1/6802312

https://gist.github.com/btm1/6746150

上面的答案之一谈论ng-repeat具有巨大的性能命中,所以我给你“一次重复”一次数据绑定重复指令:)

如果没有关于您的问题的更多信息,很难提供解决scheme,但最近我经历了(并解决了) 一个性能问题 ,这个问题可能与您所看到的类似,并且与消化周期无关。

大多数关于angularjs性能的讨论(包括来自Misko的优秀post )都是关于脏检查和$ digest循环的performance。 但是,这不是您可以用angularjs体验的唯一性能问题。 第一步应该是确定摘要循环是否是你的问题。 为此,您可以使用batarang,或者只是查看您的应用程序,以及在什么时候它正在缓慢。 当摘要周期很慢时,基本上与UI的任何交互都会很慢。

OTOH,你可以有一个快速的摘要循环的应用程序,只有在加载,切换视图或以其他方式更改要显示的组件集时才会很慢,并且这可以在分析中体现为花费在parsingHTML和垃圾上的大量时间收集。 在我的情况下,这是通过做一些预先计算的HTML模板来显示,而不是依靠ng-repeat,ng-switch,ng-if来解决。

我在窗口小部件的types中使用了一个ng-repeat =“小部件中的小部件”,以显示一组任意的小部件(自定义自包含的指令)。 用代码替代这个代码,为特定的小部件生成angular度模板,加速了从〜10s到几乎即时的路由切换。

你可以看到上面的谷歌组线程了解更多关于我如何解决我的特定问题的信息,或者如果您想要一些特定的build议,请提供关于您的应用程序的更多信息。

一般来说,如果有超过2000个数据绑定处于活动状态,那么AngularJS将performance不佳,即在脏的范围内的2000个项目 – 每个$摘要循环都会被检查。 Ng-repeat因此有很大的性能影响; 每个重复的项目至less设置两个绑定,不包括项目内使用的任何附加数据或指令。

AngularJS背后的开发者之一给出了一个很好的描述脏检查的细节,以及它在这个SO回答中的performance:

https://stackoverflow.com/a/9693933/179024

这个答案下方的评论主题值得一读,我也在同一页面的下一个答案中分享了一些想法:

https://stackoverflow.com/a/18381836/179024

为了提高生产性能,请阅读下面的一行:

引用AngularJS文档:

默认情况下,AngularJS将关于绑定和作用域的信息附加到DOM节点,并将CSS类添加到数据绑定元素:

作为ngBind,ngBindHtml或{{…}}插值的结果,绑定数据和CSS类ng-binding被附加到相应的元素。

如果编译器创build了一个新的范围,范围和ng-scope或者ng-isolated-scope CSS类都被附加到相应的元素上。 这些作用域引用可以通过element.scope()和element.isolateScope()来访问。

像Protractor和Batarang这样的工具需要运行这些信息,但是你可以在生产中禁用这个工具来显着提升性能:

myApp.config(['$compileProvider', function ($compileProvider) { $compileProvider.debugInfoEnabled(false); }]); 

你可以在这里阅读更多细节

很抱歉,因为我还没有足够的评论,所以把它作为一个“答案”。

我们已经遇到类似的问题,我们的AngularJS应用程序。 使用“batarang”似乎不得不处理大量的范围对象,并且它们相关的$ watchexpression式造成了性能上的呃逆。 这让我们想知道是否应该使用另一个框架或ReactJS来代替“视图”部分。

尝试避免以下

  1. 请避免使用ng-repeat,如果您一次有超过50个元素在列表中,并避免手动观看
  2. 不要盲目地使用ng-click,ng-mouseenter,ng-mouseleave等鼠标事件,直到它是一个迫切的需求,试着通过使用$ event对象和js的事件传播概念来减less它们的数量

  3. 哪里有可能使用范围$ digest而不是范围$ watch,这可以确保仅在子范围上执行摘要循环

    1. 尝试有一个嵌套的作用域,即一个或两个控制器在一个父控制器内,并保留可重用的逻辑在父,我使用这个嵌套状态,同时使用Ui路由器(履行要求改变url需要没有页面刷新)。

    最重要的! 从HTML中删除所有的filter!

上面的所有触发器都会在你的应用程序的所有范围内触发一个摘要循环,所以即使视图被渲染的angular度也很有可能再次执行无情的摘要循环

将DOM操作转换为自定义指令和$ watch之间的中间立场是使用“绑定一次”的语义。

一旦数据可用,对于不可变的数据来说这非常棒。 请参阅bindonce

这只会是一个链接! 这只是我阅读这个时候的一个想法,我还没有探讨过,但有人可能这样做,我正在等待他们对我的想法的答复。 如何使用共享的Web工作人员从UI线程中获取大量繁重的处理? https://github.com/h2non/sharedworkers-angular-poc

我的另一个想法是一个更简单的。 您的应用程序将受益于无限滚动吗? 我的意思是这些forms可能不适合在屏幕上,他们没有连接到彼此,所以为什么不画他们,因为他们需要? 把它们加载到内存中,然后相应地绘制它们。

就像其他性能优化一样,知道如何configuration应用程序以find真正的瓶颈是非常重要的。 然后你可以逐个解决。 我通常按​​照以下顺序来对抗瓶颈:

  • 我的JavaScript代码
  • 在每个闲置摘要周期上运行的angular度expression式(复杂的观察者和filter)
  • angular构造(ng-repeat,复制摘要循环的对象)

我已经逐步展示了一个angular度的例子,展示了如何识别每一步的瓶颈。 http://bahmutov.calepin.co/improving-angular-web-app-performance-example.html