AngularJS 中 $evalAsync 和 $timeout 有什么区别?

我已经使用 AngularJS 一段时间了,并且发现需要偶尔使用 $暂停(似乎通常是初始化一个 jQuery 插件)。

最近,我一直在试图更好和更深入地理解消化循环,我遇到了 $evalAsync功能。

看起来这个函数产生的结果与 $timeout相似,只是你不给它延迟。每次我使用 $timeout都会有0的延迟,所以现在我在想我是否应该使用 $evalAsync来代替。

这两者之间有什么根本的区别吗?什么样的案子你会用一个而不是另一个?我想知道什么时候该用哪个。

71823 次浏览

我最近在这里基本上回答了这个问题: https://stackoverflow.com/a/17239084/215945 (这个答案与一些 github 与 Misko 的交流有关。)

总结一下:

  • 如果代码是使用 $evalAsync 来自指令排队,它应该运行 之后的 DOM 已经被角操纵,但 之前的浏览器呈现
  • 如果代码是使用 来自控制器的 $evalAsync排队的,它应该运行 之前,DOM 已经被 Angular 操纵(在浏览器渲染之前)——你很少想要这样
  • 如果代码使用 $暂停排队,它应该运行 之后,DOM 已经被 Angular 操纵,浏览器呈现 之后(在某些情况下可能会导致闪烁)

对于那些构建复杂应用程序的人来说,请注意这会对您的选择产生性能影响。另外,我想用更多的技术细节来完成马克的回答:

  • $timeout (callback) 将等待当前摘要周期完成(即角度更新所有模型和 DOM) ,然后它将执行回调——可能影响角度模型——然后在根 $scope 上启动一个完整的 $apply,并重新摘要所有内容。

  • 另一方面,$evalAsync (callback) 将把回调添加到当前或下一个摘要周期。这意味着,如果您处于摘要周期内(例如,在从某个 ng-click指令调用的函数中) ,这将不等待任何事情,代码将立即执行。如果处于异步调用(例如 setTimeout)中,将触发一个新的摘要循环($apply)。

因此,就性能而言,调用 $evalAsync总是更好,除非在执行代码之前视图是最新的对您来说很重要,例如,如果您需要访问一些 DOm 属性,如元素 width 等。

如果您想了解更多关于 $timeout、 $evalAsync、 $享受、 $application 之间区别的细节,我邀请您阅读我对另一个问题的回答: https://stackoverflow.com/a/23102223/1501926

还要确保阅读 文件:

$evalAsync 不能保证何时执行表达式,只能保证:

  • 它将在计划求值的函数之后执行(最好是在 DOM 呈现之前)。
  • 在执行表达式之后,将至少执行一个 $摘要周期。

注: 如果在 $摘要循环之外调用此函数,则将安排一个新的 $摘要循环。但是,鼓励始终调用在 $application 调用中更改模型的代码。其中包括通过 $evalAsync 计算的代码。