42

我们正在为一家银行开发的 Angular 应用程序的性能问题而努力。

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

应用结构:

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

如果你看一下时间线。我们在 jQuery parse html 方法、jQuery recalculate stye 方法、GC Event (Garbage Collection) 上花费了大量时间。我想最小化这些应该会加快速度。它们都是 Angular 生命周期的一部分,但可能有更好的方法来避免它们。以下是分析器的一些屏幕截图:

重新计算样式 GC 事件

最终,由于重复表单的数量超过 5 个,应用程序变得迟缓。每个表单与其他表单相对无关。我们试图不观察表单之间的任何共享属性。

4

9 回答 9

21

您需要创建自定义指令以遏制 angular 的性能问题。与 ember angular 不同,所有的花里胡哨都打开了,你可以把它调低。以下是我为帮助您而创建的一些指令。并非您的应用程序中的所有数据都需要双向数据绑定,因此您可以通过在需要的页面中放弃监视表达式来节省宝贵的 CPU 功率。所有这些指令都一次绑定数据,然后不理会它。

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

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

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

上面的答案之一是关于 ng-repeat 具有巨大的性能影响,所以我给你“set-repeat”一个一次性数据绑定重复指令:)

于 2013-10-12T09:08:22.043 回答
8

如果没有关于您的问题的更多信息,很难提供解决方案,但我最近遇到(并解决了)一个可能与您看到的类似的性能问题,并且与 $digest 周期无关。

您会发现大多数关于 angularjs 性能的讨论(包括来自 Misko 的优秀帖子)都是关于脏检查和 $digest 循环的性能。但这不是您使用 angularjs 会遇到的唯一性能问题。第一步应该是确定消化周期是否是您的问题。为此,您可以使用batarang,或者只查看您的应用程序,看看它何时运行缓慢。当摘要周期很慢时,基本上任何与 UI 的交互都会很慢。

OTOH,您可以拥有一个具有快速消化周期的应用程序,只有在加载、切换视图或以其他方式更改要显示的组件集时才会很慢,这可以在分析中体现为花费大量时间来解析 HTML 和垃圾收集。在我的情况下,这是通过对要显示的 html 模板进行一些预计算来解决的,而不是到处依赖 ng-repeat、ng-switch、ng-if。

我使用了一个 ng-repeat="widget in widgets",其中包含一个 ng-switch 的小部件类型,以显示任意一组小部件(自定义自包含指令)。用代码替换它以生成特定小部件集的角度模板,加速了从大约 10 秒到几乎即时的路由切换。

您可以查看上面的 google 群组主题,了解有关我如何解决特定问题的更多信息,或者如果您需要一些具体建议,请提供有关您的应用程序的更多信息。

于 2013-10-01T22:47:07.913 回答
6

为了提高生产性能,请阅读以下非常好的单行:

引用 AngularJS 文档:

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

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

在编译器创建了一个新范围的地方,范围和 ng-scope 或 ng-isolated-scope CSS 类都附加到相应的元素上。然后可以通过 element.scope() 和 element.isolateScope() 访问这些范围引用。

Protractor 和 Batarang 等工具需要此信息才能运行,但您可以在生产中禁用此信息以显着提升性能:

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

您可以在此处阅读更多详细信息

于 2016-05-04T11:04:50.890 回答
3

一般来说,如果有超过 2000 个数据绑定处于活动状态,AngularJS 的性能就会很差,即每个 $digest-cycle 都会对范围内的 2000 个项目进行脏检查。因此,Ng-repeat 对性能有很大影响;每个重复的项目设置至少两个绑定,不计算项目内部使用的任何其他数据或指令。

AngularJS 背后的一位开发人员对脏检查的细节及其在这个 SO 答案中的性能进行了很好的描述:

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

该答案下方的评论线程值得一读,我还在同一页面下方的答案中分享了一些关于它的想法:

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

于 2013-09-10T17:16:50.363 回答
2

很抱歉将其作为“答案”,因为我还没有足够的分数来发表评论。

我们的 AngularJS 应用程序也遇到了类似的问题。使用 'batarang' 似乎必须处理大量范围对象,并且它们相关的 $watch 表达式会产生性能问题。这让我们想知道是否应该使用另一个框架或类似 ReactJS 的东西来处理“视图”部分。

于 2014-01-03T11:36:00.843 回答
2

尽量避免以下

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

  3. 尽可能使用 scope.$digest 而不是 scope.$watch,这样可以确保仅在子作用域上执行摘要循环

    1. 尝试在一个父控制器中使用嵌套范围,即一个或两个控制器,并将可重用逻辑保留在父控制器中,我在使用 Ui-router 时在嵌套状态下使用它(以满足需要更改 URL 而无需刷新页面的请求)。

    最重要的!从 HTML 中删除所有过滤器!

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

于 2014-02-22T18:53:23.513 回答
1

将 DOM 操作移动到自定义指令和大量 $watch 的 $watch 问题之间的中间立场是使用“bind-once”语义。

这对于一旦数据可用就不可改变的数据非常有用。见绑定

于 2014-02-21T10:41:04.577 回答
0

这将只是一个链接!这只是我在阅读本文时的一个想法,我还没有探索过这个,但可能有人这样做了,所以我正在等待他们对我的想法的回复。如何使用共享网络工作者从 ui 线程中获得大量繁重的处理?https://github.com/h2non/sharedworkers-angular-poc

我的另一个想法是一个更简单的想法。您的应用会从无限滚动中受益吗?我的意思是这些表格可能并不都适合屏幕,它们没有相互连接,所以为什么不根据需要绘制它们呢?将它们加载到内存中,然后相应地绘制它们。

于 2014-05-08T13:04:25.597 回答
0

就像在任何其他性能优化中一样,了解如何分析应用程序以找到真正的瓶颈非常重要。然后你就可以一一解决了。我通常按​​以下顺序对抗瓶颈:

  • 我的 JavaScript 代码
  • 在每个空闲摘要周期运行的角度表达式(复杂的观察者和过滤器)
  • 角度构造(ng-repeat,复制摘要循环的对象)

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

于 2014-10-28T17:37:13.543 回答