AngularJS: 当调用 $scope.$apply() 时,防止出现错误 $digest already in progress。
AngularJS: 当调用 $scope.$apply() 时,防止出现错误 $digest already in progress。
在使用Angular构建应用程序后,我发现越来越需要手动更新我的页面以匹配我的作用域。
我所知道的唯一方法是从我的控制器和指令的作用域调用$apply()
。但问题是它会持续向控制台抛出以下错误:
错误:$digest已在进行中
有人知道如何避免这个错误或以不同的方式实现相同的功能吗?
不要使用这个模式 - 这会导致比解决更多的错误。即使你认为它修复了某些问题,其实并没有。
你可以通过检查 $scope.$$phase
来判断是否已经有一个 $digest
正在进行中。
if(!$scope.$$phase) { //$digest or $apply }
$scope.$$phase
如果有一个 $digest
或 $apply
正在进行中,它将返回 "$digest"
或 "$apply"
。我认为这两种状态之间的区别在于,$digest
将处理当前范围及其子级的观察者,而 $apply
将处理所有作用域的观察者。
关于 @dnc253 的观点,如果你经常调用 $digest
或 $apply
,你可能做错了。我通常会发现,当需要更新作用域状态以响应 Angular 之外的 DOM 事件时,我需要进行 digest。例如,当 Twitter Bootstrap 模态框变为隐藏状态时。有时 DOM 事件会在 $digest
进行中触发,有时不会。这就是为什么我使用这个检查。
我很想知道是否有更好的方法,如果有人知道的话。
从评论中得知:by @anddoutoi
- 不要这样做
if (!$scope.$$phase) $scope.$apply()
,这意味着你的$scope.$apply()
没有在调用堆栈中的层级足够高。
最近与Angular小伙伴们就这个问题进行了讨论:出于未来的保护,你不应该使用$$phase
当被追问什么是“正确”的方法时,目前的答案是
$timeout(function() { // anything you want can go here and will safely be run on the next digest. })
我最近在编写Angular服务以包装Facebook、Google和Twitter API时遇到了这个问题,这些API在不同程度上都有回调函数。
以下是服务中的一个示例。(为了简洁起见,这里省略了其余设置变量、注入$timeout等内容的服务)
window.gapi.client.load('oauth2', 'v2', function() { var request = window.gapi.client.oauth2.userinfo.get(); request.execute(function(response) { // This happens outside of angular land, so wrap it in a timeout // with an implied apply and blammo, we're in action. $timeout(function() { if(typeof(response['error']) !== 'undefined'){ // If the google api sent us an error, reject the promise. deferred.reject(response); }else{ // Resolve the promise with the whole response if ok. deferred.resolve(response); } }); }); });
请注意,$timeout的延迟参数是可选的,如果未设置,它将默认为0($timeout调用$browser.defer,如果未设置延迟,则默认为0)
虽然有点不直观,但这是Angular编写者的答案,所以对我来说已经足够好了!