我发现我需要手动更新我的页面到我的范围越来越多,因为构建一个应用程序的角度。
我知道的唯一方法就是从控制器和指令的范围调用$apply()。这样做的问题是,它不断向控制台抛出一个错误,该控制台读取:
错误:$digest已经在进行中
有没有人知道如何避免这一错误,或者以不同的方式实现相同的目标?
发布于 2013-09-25 04:06:19
根据最近与角质人就这个主题进行的讨论:出于未来的考虑,您不应该使用$$phase 。
当按下“正确”的方法做这件事时,答案是
$timeout(function() {
// anything you want can go here and will safely be run on the next digest.
})最近,我在编写棱角服务来包装facebook、google和twitter时遇到了这种情况,这些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)
有点不直观,但这是男人写角度的答案,所以对我来说已经足够好了!
发布于 2013-07-30 22:51:27
摘要周期是一个同步调用。在完成之前,它不会将控制权让给浏览器的事件循环。有几种方法可以解决这个问题。处理这一问题的最简单方法是使用内置的$timeout,第二种方法是如果使用下划线或存档(应该是),调用以下命令:
$timeout(function(){
//any code in here will automatically have an apply run afterwards
});或者如果你有房客:
_.defer(function(){$scope.$apply();});我们尝试了几种解决方案,我们讨厌将$rootScope注入到所有控制器、指令甚至一些工厂中。因此,到目前为止,$timeout和_.defer一直是我们的最爱。这些方法成功地告诉角直到下一个动画循环,这将保证当前范围。$apply已经结束。
发布于 2014-04-16 06:59:44
这里的许多答案包含了很好的建议,但也可能导致混淆。简单地使用$timeout不是最好的解决方案,也不是正确的解决方案。此外,如果您关心性能或可伸缩性,请务必阅读。
你应该知道的事
$$phase对框架是私有的,这是有充分理由的。$timeout(callback)将等待当前摘要周期(如果有的话)完成,然后执行回调,然后在结束时运行一个完整的$apply。$timeout(callback, delay, false)也会这样做(在执行回调之前有一个可选的延迟),但是不会触发一个$apply (第三个参数),如果您不修改角度模型($scope),这会节省性能。$scope.$apply(callback)除其他外调用$rootScope.$digest,这意味着它将重新消化应用程序的根范围及其所有子级,即使您是在一个独立的范围内。$scope.$digest()将简单地将其模型同步到视图,但不会消化它的父作用域,这可以在使用隔离作用域(大部分来自指令)处理HTML的孤立部分时节省大量性能。$digest不接受回调:您执行代码,然后消化。$scope.$evalAsync(callback)是在angularjs1.2中引入的,可能会解决大部分问题。请参考最后一段来了解更多。$digest already in progress error,那么您的体系结构是错误的:要么您不需要重新消化您的范围,要么您不应该负责这个问题(参见下面)。如何构造代码
当您得到这个错误时,您正在尝试消化您的作用域,而它已经在进行中:由于您不知道您的作用域在那时的状态,所以您不负责处理它的消化。
function editModel() {
$scope.someVar = someVal;
/* Do not apply your scope here since we don't know if that
function is called synchronously from Angular or from an
asynchronous code */
}
// Processed by Angular, for instance called by a ng-click directive
$scope.applyModelSynchronously = function() {
// No need to digest
editModel();
}
// Any kind of asynchronous code, for instance a server request
callServer(function() {
/* That code is not watched nor digested by Angular, thus we
can safely $apply it */
$scope.$apply(editModel);
});如果您知道自己在做什么,并且在大角度应用程序中使用一个孤立的小指令,那么您可以选择$digest而不是$apply来保存性能。
自Angularjs 1.2以来的更新
在任何$scope:$evalAsync中都添加了一个新的、强大的方法。基本上,如果出现一个摘要周期,它将在当前摘要周期内执行回调,否则一个新的摘要周期将开始执行回调。
如果您真的知道您只需要同步HTML中的一个独立部分(因为如果没有正在进行的话,就会触发一个新的$apply ),那么这仍然不如$apply好,但是当您正在执行一个您不知道是否将同步执行的函数时,这是最好的解决方案,例如在获取可能缓存的资源之后:有时这将需要对服务器进行异步调用,否则资源将在本地同步获取。
在这些情况下和所有其他有!$scope.$$phase的地方,一定要使用$scope.$evalAsync( callback )
https://stackoverflow.com/questions/12729122
复制相似问题