指令测试中的 $apply 与 $digest

Posted

技术标签:

【中文标题】指令测试中的 $apply 与 $digest【英文标题】:$apply vs $digest in directive testing 【发布时间】:2013-09-12 21:55:07 【问题描述】:

如果我有一个指令响应范围上特定属性的状态,并且我想在我的测试中更改该属性并验证它是否正确响应,那么执行该更改的最佳方法是什么?

这两种模式我都见过:

scope.$apply(function() 
    scope.myAttribute = true;
);

scope.myAttribute = true;
scope.$digest();

它们之间有什么区别,哪个更好,为什么?

【问题讨论】:

【参考方案1】:

scope.$digest() 将在当前作用域及其所有子作用域上触发观察者。 scope.$apply 将评估传递的函数并运行 $rootScope.$digest()

第一个更快,因为它需要评估当前范围及其子范围的观察者。第二个比较慢,因为它需要评估$rootScope 及其所有子作用域的观察者。

当其中一个观察者发生错误并且您使用scope.$digest 时,它不会通过$exceptionHandler 服务处理,因此您需要自己处理异常。 scope.$apply 在内部使用 try-catch 块并将所有异常传递给 $exceptionHandler

【讨论】:

$digest 也会被调用到作用域的孩子上吗? 这可能会产生误导。 $digest 不仅会在当前范围内触发观察者,还会在其所有子级上触发。 @tasseKATT,我想我已经理解了您的评论所暗示的内容。【参考方案2】:

正如文档本身所提到的,$digest 循环在您执行$scope.$apply 的任何时候都会执行。根据scope的开发者指南@

计算表达式后,$apply 方法执行 $digest。 在 $digest 阶段,作用域检查所有 $watch 表达式 并将它们与之前的值进行比较。

根据 Scope API documentation

通常你不会直接在控制器中调用 $digest() 或 指令。而是调用 $apply() (通常来自 指令)将强制执行 $digest()。

所以你不应该显式调用$digest,你调用$apply方法会触发一个摘要循环。

【讨论】:

这是不正确的,因为对于大多数只需要评估当前范围及其子范围的情况,摘要就足够了。确实 $scope.$apply 在内部调用 $digest 但记住它最终会调用 $rootScope.$digest() 并因此非常重

以上是关于指令测试中的 $apply 与 $digest的主要内容,如果未能解决你的问题,请参考以下文章

理解Angular中的$apply()以及$digest()

理解Angular中的$apply()以及$digest()

理解Angular中的$apply()以及$digest()

理解Angular中的$apply()以及$digest()

理解Angular中的$apply()以及$digest()

深入理解Angular中的$apply()以及$digest()