wiki
wiki copied to clipboard
避免调用$scope.$apply()时发生$digest already in progress错误
在使用Angular的时候避免不了经常手动更新作用域的情况,特别是在指令中。通常是用 controller 和 directives 的 $apply()
来手动触发 $digest
的。不过直接用它的话,有一定机率会在控制台抛出错误:
Error: $digest already in progress
很多第三方指令中,包括 ui-event 都是这样写来避免报错的:
if (!$scope.$$phase) {
$scope.$apply();
}
$$phase
是一个标志,是否angular 在$digest
循环中。如果$digest
循环中 ,$scope.$$phase
会返回true。
但是官方不建议我们这么做 When-to-use-$scope.$apply():
Do NOT randomly sprinkle it throughout your code. If you are doing if (!$scope.$$phase) $scope.$apply() it's because you are not high enough in the call stack.
最好不要用 $$phase
正确的方式是:
$timeout(function() {
// anything you want can go here and will safely be run on the next digest.
})
或者
$scope.$evalAsync(function(){
// ....
})
你应该知道的一些细节:
-
$$phase
is private to the framework and there are good reasons for that. -
$timeout(callback)
will wait until the current digest cycle (if any) is done, then execute the callback, then run at the end a full $apply. -
$timeout(callback, delay, false)
will do the same (with an optional delay before executing the callback), but will not fire an $apply (third argument) which saves performances if you didn't modify your Angular model ($scope). -
$scope.$apply(callback)
invokes, among other things, $rootScope.$digest, which means it will redigest the root scope of the application and all of its children, even if you're within an isolated scope. -
$scope.$digest()
will simply sync its model to the view, but will not digest its parents scope, which can save a lot of performances when working on an isolated part of your HTML with an isolated scope (from a directive mostly). $digest does not take a callback: you execute the code, then digest. -
$scope.$evalAsync(callback)
has been introduced with angularjs 1.2, and will probably solve most of your troubles. - if you get the
$digest already in progress error
, then your architecture is wrong: either you don't need to redigest your scope, or you should not be in charge of that.
参考:
解决了实际的问题,非常有用,感谢分享!