39

我们正在针对我们正在为银行开发的Angular应用程序的性能问题猛击我们的头脑。Angular JS缩放与性能

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

应用结构:

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

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

Recalculate Style GC Event

最终,应用程序是作为呆滞的重复形式的数量变得高于5.每一形式相对无关的其他人。我们试图不注意表单之间的任何共享属性。

+2

,问题是。 ..? – Stewie

+0

你有没有试过追溯这个函数调用到你自己的代码库(或角度调用它?)的代码?@Stewie我相信这个问题(尽管有点编纂)是什么是可能出现的一般性能瓶颈在AngularJS应用程序中?应该如何处理性能/优化?我相信Chrome的Batarang插件有一些性能(只是检查,当然确实有一个性能选项卡,虽然我没有使用它,它可能会有所帮助)。 – shaunhusain

+1

“AngularJS应用程序中可能会出现什么性能瓶颈?”与任何JavaScript应用程序相同的瓶颈,您创建对象越多,GC的时间就越长。 HTML5rocks网站上有很多关于此的资源。 – mpm

回答

3

通常情况下,如果有超过2000个数据绑定处于活动状态,那么AngularJS将表现不佳,即正在脏的范围内的2000个项目 - 每个$ digest-cycle都会被检查。由于这个原因,Ng-repeat的性能影响很大;每个重复的项目至少设置两个绑定,不包括项目内使用的任何附加数据或指令。

一个背后AngularJS开发商给出的脏检查的细节极好的描述,其在此表现如此回答:

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

这个问题的答案下面的评论线程是值得一读,我也分享一些关于它的想法在回答中进一步下跌的同一页上:

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

+0

我认为米斯科的回答虽然很好,但只部分解决了这个问题。这个问题的一大部分似乎是Angular正在单独创建每个元素,而不是将它们分配到同一个碎片中。 – DNS

+0

问题可能仅仅在于,通过多个重复表单,每个表单中的每个重复表单都有多个重复的项目,每次运行$ digest时都会监视的项目数量会导致站点变慢。一个很好的方法来检查这将是Chrome的batarang插件,它将实时显示摘要时间。但由于OP无法显示任何代码,因此查明问题很难。 –

+2

OP确实显示了事件时间表,大部分显示的活动都是一系列HTML解析。 Angular可能有这样一个充分的理由,而不是在一个片段中创建它们,但我认为这就是为什么它在这里慢;肮脏的检查似乎不是一个很大的贡献者。 – DNS

7

很难提供一个解决方案没有更多的信息关于你的问题,但我最近经历了(并解决了)a performance issue,可能与你所看到的相似,并且与$消化周期无关。

大多数关于angularjs性能的讨论(包括excellent post from Misko)都是关于脏检查和$ digest循环的性能。但这不是您可以通过angularjs体验的唯一性能问题。第一步应该是确定摘要循环是否是你的问题。为此,您可以使用batarang,或者只是查看您的应用程序,以及何时精确缓慢。当摘要周期较慢时,基本上与UI的任何交互都会很慢。您可以拥有快速摘要循环的应用程序,只有在加载,切换视图或以其他方式更改要显示的组件集时才会很慢,并且这可以在分析中体现为大量时间花费在解析HTML和垃圾收集。在我的情况下,这是通过执行HTML模板来显示的一些预先计算的,而不是依靠NG重复,NG-开关,NG-如果到处都是解决。

在我正在使用纳克重复=“微件在微件”含有关于微件的类型的NG-开关,为了显示窗口小部件的任意集合(定制自包含指令)。将其替换为代码以生成特定组件的角度模板,加快了从〜10s到几乎即时的路由切换速度。

你可以看到谷歌组纱线之上多一点信息我如何解决我的具体问题,或者如果你想一些具体的建议提供有关应用程序的更多信息。

+0

您是否仍然使用这种方法获得2路数据绑定? – Matheus

+0

@matheus:是的,每个小部件的内容仍然有双向绑定。另一方面,要显示的小部件列表没有,它是通过连接每个单独小部件的模板生成的。 – jssebastian

20

你需要为了遏制与棱角分明的性能问题来创建自定义指令。与余烬不同,随着所有的钟声和口哨声开启,您可以调整它。以下是我创建的一些帮助你的指令。并非您的应用中的所有数据都需要双向数据绑定,因此您可以通过在需要的页面中放置监视表达式来节省宝贵的CPU功耗。所有这些指令都将数据绑定一次,并保持独立。

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

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

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

一个以上大约有巨大的性能NG-重复谈判的答案打,所以我给你“设置重复”一次性数据绑定重复指令: )

2

很抱歉,对于把它作为一个“答案”,因为我没有足够的积分尚未作出评论。

我们遇到了与我们的AngularJS应用类似的问题。使用'batarang'似乎不得不处理大量的范围对象,并且它们相关的$ watch表达式会导致性能呃逆。这让我们想知道是否应该使用另一个框架或类似ReactJS来处理“视图”部分。

1

将DOM操作转换为自定义指令和许多$ watch的$ watch问题之间的中间地带是使用“绑定一次”语义。

这对于一旦数据可用后不可变的数据很有用。见bindonce

2

尽量避免以下

  1. 请避免使用NG-重复,如果你有 超过50个元素列表的时间和避免人工手表
  2. 不使用NG-点击,ng-mouseenter,ng-mouseleave等鼠标事件,直到它是一个迫切的需求,尝试通过使用$事件对象以及js的事件传播概念来减少它们的数量

  3. 哪里有可能使用范围$ digest instea d范围。$ watch,这可以确保仅在子范围内执行摘要循环

    1. 尝试嵌套作用域,即一个或两个控制器位于一个父控制器内并将可重用逻辑保留在父对象中,i在使用Ui路由器时使用这种嵌套状态(以满足需要更改URL而无需刷新页面的请求)。

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

上述所有触发您的应用程序的所有范围摘要周期等方面有很高的概率,即使当视图已经被渲染的角度再次执行无情消化循环

+2

你会用什么来代替ng-click和ng-repeat? –

+0

使用事件捕获和冒泡的javascript概念来减少ng-click和ng-repeat使用单个绑定属性(更新版本的角度js) –

+0

我不会违背谷物,除非你遇到性能问题或者知道你会。防爆。如果你没有使用事件的内置指令,如果你想更新你的模型,你会被触发。$ digest()(触发从当前范围向下的脏检查)或更糟糕的$ apply()()这会从$ rootScope中触发),这比使用ng-click或其他方法(其只为该范围注册另一个观察者)效率低。 – TaylorMac

0

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

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

0

就像其他任何性能优化一样,知道如何配置应用程序以查找真正的瓶颈非常重要。然后你可以逐个解决它们。我平时打的瓶颈以下顺序:

  • 我的javascript代码
  • 角度表达式(复杂的观察家和过滤器),其在每个空闲消化周期运行
  • 角结构(NG-重复,复制的对象Digest循环)

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

3

为了提高生产性能阅读非常漂亮下面的一行:

报价AngularJS文档:

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

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

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

工具,比如量角器和Batarang需要这些信息来运行,但你可以在生产中使用禁用此一显著的性能提升:

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

你可以阅读更多细节here