AngularJS:在调用$ scope时防止错误$ digest正在进行中。$ apply()

孟智志
2023-12-01

本文翻译自:AngularJS : Prevent error $digest already in progress when calling $scope.$apply()

I'm finding that I need to update my page to my scope manually more and more since building an application in angular. 我发现自从以角度构建应用程序后,我需要越来越多地手动将页面更新到我的范围。

The only way I know of to do this is to call $apply() from the scope of my controllers and directives. 我知道这样做的唯一方法是从我的控制器和指令的范围调用$apply() The problem with this is that it keeps throwing an error to the console that reads : 这个问题是它不断向控制台抛出一个错误:

Error: $digest already in progress 错误:$ digest已在进行中

Does anyone know how to avoid this error or achieve the same thing but in a different way? 有谁知道如何避免这个错误或以不同的方式实现相同的事情?


#1楼

参考:https://stackoom.com/question/rPQQ/AngularJS-在调用-scope时防止错误-digest正在进行中-apply


#2楼

When you get this error, it basically means that it's already in the process of updating your view. 当您收到此错误时,它基本上意味着它已经在更新您的视图。 You really shouldn't need to call $apply() within your controller. 你真的不需要在你的控制器中调用$apply() If your view isn't updating as you would expect, and then you get this error after calling $apply() , it most likely means you're not updating the the model correctly. 如果您的视图没有按预期更新,然后在调用$apply()后出现此错误,则很可能意味着您没有正确更新模型。 If you post some specifics, we could figure out the core problem. 如果你发布一些细节,我们可以找出核心问题。


#3楼

Don't use this pattern - This will end up causing more errors than it solves. 不要使用这种模式 - 这最终会导致比它解决的更多错误。 Even though you think it fixed something, it didn't. 即使你认为它固定了一些东西,它也没有。

You can check if a $digest is already in progress by checking $scope.$$phase . 您可以通过检查$scope.$$phase来检查$scope.$$phase $digest是否已在进行中。

if(!$scope.$$phase) {
  //$digest or $apply
}

$scope.$$phase will return "$digest" or "$apply" if a $digest or $apply is in progress. 如果$digest$apply正在进行中, $scope.$$phase将返回"$digest""$apply" I believe the difference between these states is that $digest will process the watches of the current scope and its children, and $apply will process the watchers of all scopes. 我相信这些状态之间的区别在于$digest将处理当前范围及其子项的监视, $apply将处理所有范围的观察者。

To @dnc253's point, if you find yourself calling $digest or $apply frequently, you may be doing it wrong. 对于@ dnc253来说,如果你发现自己经常叫$digest$apply ,你可能做错了。 I generally find I need to digest when I need to update the scope's state as a result of a DOM event firing outside the reach of Angular. 我通常发现当需要更新范围的状态时,我需要消化,因为DOM事件在Angular的范围之外触发​​。 For example, when a twitter bootstrap modal becomes hidden. 例如,当twitter引导模式变为隐藏时。 Sometimes the DOM event fires when a $digest is in progress, sometimes not. 有时,当$digest正在进行时,DOM事件会触发,有时则不会。 That's why I use this check. 这就是我使用这张支票的原因。

I would love to know a better way if anyone knows one. 如果有人知道,我很想知道一个更好的方法。


From comments: by @anddoutoi 来自评论:@anddoutoi

angular.js Anti Patterns angular.js反模式

  1. Don't do if (!$scope.$$phase) $scope.$apply() , it means your $scope.$apply() isn't high enough in the call stack. 不要做if (!$scope.$$phase) $scope.$apply() ,这意味着你的$scope.$apply()在调用堆栈中不够高。

#4楼

Sometimes you will still get errors if you use this way ( https://stackoverflow.com/a/12859093/801426 ). 如果您使用这种方式,有时您仍会遇到错误( https://stackoverflow.com/a/12859093/801426 )。

Try this: 试试这个:

if(! $rootScope.$root.$$phase) {
...

#5楼

Handy little helper method to keep this process DRY: 方便的小助手方法来保持这个过程干燥:

function safeApply(scope, fn) {
    (scope.$$phase || scope.$root.$$phase) ? fn() : scope.$apply(fn);
}

#6楼

The digest cycle is a synchronous call. 摘要周期是同步调用。 It won't yield control to the browser's event loop until it is done. 在完成之前,它不会控制浏览器的事件循环。 There are a few ways to deal with this. 有几种方法可以解决这个问题。 The easiest way to deal with this is to use the built in $timeout, and a second way is if you are using underscore or lodash (and you should be), call the following: 解决这个问题最简单的方法是使用内置的$ timeout,第二种方法是使用下划线或lodash(你应该这样),请调用以下内容:

$timeout(function(){
    //any code in here will automatically have an apply run afterwards
});

or if you have lodash: 或者如果你有lodash:

_.defer(function(){$scope.$apply();});

We tried several workarounds, and we hated injecting $rootScope into all of our controllers, directives, and even some factories. 我们尝试了几种解决方法,我们讨厌将$ rootScope注入我们的所有控制器,指令甚至一些工厂。 So, the $timeout and _.defer have been our favorite so far. 所以,到目前为止,$ timeout和_.defer一直是我们的最爱。 These methods successfully tell angular to wait until the next animation loop, which will guarantee that the current scope.$apply is over. 这些方法成功地告诉angular等待下一个动画循环,这将保证当前范围。$ apply结束。

 类似资料: