AngularJS: $eval需要很长时间

5
在对我的angularjs应用程序进行分析时,我发现有时候$get.Scope.$eval需要超过100毫秒的时间。在单个$digest循环中,至少有3个长时间的$get.Scope.$eval情况,我想优化这部分。
在分析器中,我只看到了调用angularjs代码之后的$get.Scope.$eval
以下是分析图表的截图。

enter image description here

请问有人能够建议一下,发生了什么以及如何优化这部分代码?我认为这可能是由于ng-repeatng-includeng-if引起的,但我不确定。

更新: 这是我应用程序的简化结构。可能问题在于我的应用程序架构。该应用程序大多数情况下都在单一路由上工作,并且仅在三种情况下更改它,因此应用程序将状态存储在全局控制器AppController中 - 肥大的控制器。此外,HTML中有20k+节点,数量可能会增长(我看到的最大值是60k)。

1个回答

1

$eval在解析angular表达式(例如{{variable}})时在内部使用。如果没有看到你的代码,很难判断哪些表达式不必要地消耗了资源,但通常过于庞大或嵌套的ng-repeat(或许多包含在ng-repeat中的ng-指令)是一个代码坏味道。

Angular使用脏检查来评估这些表达式(因为没有更好的选择) - 这意味着每次使用{{}}语法创建绑定时,它都会创建一个隐式的$watch表达式来获取该值,该表达式将在每个digest周期调用以查看该值是否已更改(在更改时重新生成DOM的相关部分)。

以下是我过去成功使用的一种优化:

大多数情况下,当您使用{{}}绑定值时,实际上并不希望该值发生变化(例如标签),并且这种双向数据绑定是完全多余的。自angular 1.3版本以来,您可以使用::语法创建一次性绑定

一次性表达式在稳定后会停止重新计算,如果表达式结果是非undefined值,则在第一次digest之后发生

这消除了此类绑定的相应性能开销。(如果您使用较旧的angular版本,则外部库可以模拟此行为,例如bindonce。)

以下是我在分析/优化angular应用程序时发现有用的其他工具:

  • Batarang,一款用于调试和分析Angular应用程序的Chrome扩展。
  • 这个stackoverflow答案提供了一个简洁的解决方案来计算页面上有多少个监视表达式。 一个经验法则是,如果您超过2000个,就会开始注意到性能问题,并且您应该考虑更改架构 - 使用惰性加载机制,重新考虑是否真正需要所有绑定等。

  • 在生产环境中,禁用Angular的默认“调试模式”也可以帮助提高性能。


谢谢!不幸的是,我已经使用了and::,以及Batarang并尝试减少观察者的数量。我只有不到2k个观察者,但应用程序非常缓慢。可能我使用的架构是错误的,但这是另一个问题。 - uladzimir
关于架构方面,我的代码中有很多 ng-ifng-showng-repeat,但没有改变路由。每当用户执行操作后,我的 300 多个作用域都需要被消化。可能 $eval 尝试评估我的嵌套 ng-include 中的大量内容,但我不确定,正在尝试通过提问来理解它。 - uladzimir
300+个活动范围听起来像是一场噩梦,无论是在性能还是可维护性方面。你确定你需要同时使用所有这些吗?你能给我们一些更复杂的嵌套结构的代码示例吗? - doldt
可以,但这可能是一个比当前问题更常见的问题。稍后我会添加代码结构示意图。 - uladzimir
这里是代码的简化结构 https://gist.github.com/havenchyk/c1c668de6bc112ea93f2#file-code-md我只为3种情况更改路由,因此大多数应用程序将状态存储在全局控制器AppCtrl中。 - uladzimir
你应该将这些注释编辑到你的原始问题中,这样人们才能看到并适当地回答。 - doldt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接