Skip to content
This repository has been archived by the owner on Mar 23, 2021. It is now read-only.

避免调用$scope.$apply()时发生$digest already in progress错误 #6

Open
huguangju opened this issue Nov 5, 2015 · 1 comment

Comments

@huguangju
Copy link
Owner

在使用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.

参考:

  1. AngularJS : Prevent error $digest already in progress when calling $scope.$apply()
  2. Why is using if(!$scope.$$phase) $scope.$apply() an anti-pattern?
  3. What is $$phase in AngularJS?
@HiKWang
Copy link

HiKWang commented Aug 10, 2017

解决了实际的问题,非常有用,感谢分享!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants