我发现自从在angular中构建应用程序以来,我越来越需要手动将页面更新到我的范围。
我知道的唯一方法是从控制器和指令的范围调用$apply()。这样做的问题是,它不断向控制台抛出一个错误,错误如下:
错误:$digest已在进行中
有人知道如何避免这种错误或以不同的方式实现相同的事情吗?
我发现自从在angular中构建应用程序以来,我越来越需要手动将页面更新到我的范围。
我知道的唯一方法是从控制器和指令的范围调用$apply()。这样做的问题是,它不断向控制台抛出一个错误,错误如下:
错误:$digest已在进行中
有人知道如何避免这种错误或以不同的方式实现相同的事情吗?
当前回答
使用$scope$$阶段||$scope$apply();相反
其他回答
这是我的utils服务:
angular.module('myApp', []).service('Utils', function Utils($timeout) {
var Super = this;
this.doWhenReady = function(scope, callback, args) {
if(!scope.$$phase) {
if (args instanceof Array)
callback.apply(scope, Array.prototype.slice.call(args))
else
callback();
}
else {
$timeout(function() {
Super.doWhenReady(scope, callback, args);
}, 250);
}
};
});
这是它的用法示例:
angular.module('myApp').controller('MyCtrl', function ($scope, Utils) {
$scope.foo = function() {
// some code here . . .
};
Utils.doWhenReady($scope, $scope.foo);
$scope.fooWithParams = function(p1, p2) {
// some code here . . .
};
Utils.doWhenReady($scope, $scope.fooWithParams, ['value1', 'value2']);
};
当您收到此错误时,基本上意味着它已经在更新视图的过程中。您真的不需要在控制器中调用$apply()。如果您的视图没有按预期进行更新,并且在调用$apply()后出现此错误,那么很可能意味着您没有正确更新模型。如果你发布一些细节,我们可以找出核心问题。
您应该根据上下文使用$evalAsync或$timeout。
这是一个有很好解释的链接:
http://www.bennadel.com/blog/2605-scope-evalasync-vs-timeout-in-angularjs.htm
不要使用这种模式-这将导致比它解决的错误更多的错误。即使你认为它修复了一些东西,但它没有。
您可以通过检查$scope来检查$digest是否已在进行中$$阶段
if(!$scope.$$phase) {
//$digest or $apply
}
$范围$$如果正在进行$digest或$apply,则阶段将返回“$digest”或“$apply”。我认为这些状态之间的区别在于,$digest将处理当前范围及其子范围的监视,而$apply将处理所有范围的监视。
就@dnc253而言,如果你发现自己经常调用$digest或$apply,那么你可能做得不对。我通常发现,当我需要更新作用域的状态时,我需要进行消化,因为DOM事件超出Angular的范围。例如,当twitter引导模式变为隐藏时。有时,当$digest正在进行时,DOM事件会触发,有时则不会。这就是我用这张支票的原因。
如果有人知道,我很想知道更好的方法。
来自评论:作者@anddoutoi
angular.js反模式
不执行if(!$scope.$$phase)$scope$apply(),表示$scope$apply()在调用堆栈中不够高。
let $timeoutPromise = null;
$timeout.cancel($timeoutPromise);
$timeoutPromise = $timeout(() => {
$scope.$digest();
}, 0, false);
以下是避免此错误和避免$apply的好解决方案
如果基于外部事件调用,则可以将其与反跳(0)结合使用。以上是我们正在使用的“反跳”,以及完整的代码示例
.factory('debounce', [
'$timeout',
function ($timeout) {
return function (func, wait, apply) {
// apply default is true for $timeout
if (apply !== false) {
apply = true;
}
var promise;
return function () {
var cntx = this,
args = arguments;
$timeout.cancel(promise);
promise = $timeout(function () {
return func.apply(cntx, args);
}, wait, apply);
return promise;
};
};
}
])
以及代码本身,以侦听某些事件并仅在需要的$scope上调用$digest
let $timeoutPromise = null;
let $update = debounce(function () {
$timeout.cancel($timeoutPromise);
$timeoutPromise = $timeout(() => {
$scope.$digest();
}, 0, false);
}, 0, false);
let $unwatchModelChanges = $scope.$root.$on('updatePropertiesInspector', function () {
$update();
});
$scope.$on('$destroy', () => {
$timeout.cancel($update);
$timeout.cancel($timeoutPromise);
$unwatchModelChanges();
});