堆栈追踪:
Error: $apply already in progress
at Error (<anonymous>)
at beginPhase (file:///android_asset/www/built.min.js:7:22740)
at Object.Scope.$apply (file:///android_asset/www/built.min.js:7:25967)
at navigator.geolocation.getCurrentPosition.that (file:///android_asset/www/built.min.js:13:8670)
at Object.geolocation.getCurrentPosition (file:///android_asset/www/plugins/org.apache.cordova.core.geolocation/www/geolocation.js:122:13)
at Object.getCurrentPosition (file:///android_asset/www/built.min.js:13:8589)
at Object.getCurrentPosition (file:///android_asset/www/built.min.js:13:8277)
at Object.getCurrentCity (file:///android_asset/www/built.min.js:13:8941)
at Object.$scope.locateDevice (file:///android_asset/www/built.min.js:13:10480)
at file:///android_asset/www/built.min.js:7:12292:7
引用此代码http://pastebin.com/B9V6yvFu
getCurrentPosition: cordovaReady(function (onSuccess, onError, options) {
navigator.geolocation.getCurrentPosition(function () {
var that = this,
args = arguments;
if (onSuccess) {
$rootScope.$apply(function () {
onSuccess.apply(that, args);
});
}
}, function () {
var that = this,
args = arguments;
if (onError) {
$rootScope.$apply(function () {
onError.apply(that, args);
});
}
}, {
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 18000000
});
})
奇怪的是,在我的LG4X上它工作正常,但是在我的三星s2上它抛出了上述错误。任何想法都错了吗?
答案 0 :(得分:101)
您收到此错误是因为您在现有的消化周期内调用了$apply
。
最大的问题是:你为什么打电话给$apply
?除非您从非Angular事件接口,否则您不应该呼叫$apply
。 $apply
的存在通常意味着我做错了(除非,$ apply适用于非Angular事件)。
如果此处$apply
确实合适,请考虑使用“安全申请”方法:
答案 1 :(得分:56)
只需使用$evalAsync代替$apply
。
答案 2 :(得分:38)
您可以使用以下声明:
if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') {
$scope.$apply();
}
答案 3 :(得分:22)
如果在某些情况下必须应用范围,那么您可以设置超时,以便$ apply延迟到下一个刻度
setTimeout(function(){ scope.$apply(); });
或将您的代码包装在$ timeout(function(){..});因为它会在执行结束时自动$应用范围。如果你需要你的功能同步,我会先做。
答案 4 :(得分:9)
在角度1.3中,我认为,他们添加了一个新功能 - $scope.$applyAsync()
。此函数调用稍后应用 - 他们至少在10毫秒后说。它并不完美,但它确实至少消除了烦人的错误。
https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope#$ applyAsync
答案 5 :(得分:8)
在我的情况下,我使用带有角度日历UI的$apply
来链接某个事件:
$scope.eventClick = function(event){
$scope.$apply( function() {
$location.path('/event/' + event.id);
});
};
阅读问题文档后:https://docs.angularjs.org/error/ $ rootScope / inprog
部分不一致的 API(同步/异步)非常有趣:
例如,假设第三方库有一个方法可以为我们检索数据。由于它可能正在对服务器进行异步调用,因此它接受一个回调函数,该函数将在数据到达时被调用。
因为MyController构造函数总是在$ apply调用中实例化,所以我们的处理程序试图从一个内部输入一个新的$ apply块。
我将代码更改为:
$scope.eventClick = function(event){
$timeout(function() {
$location.path('/event/' + event.id);
}, 0);
};
像魅力一样!
这里我们使用$ timeout来调度未来调用堆栈中范围的更改。通过提供0ms的超时时间,这将尽快发生,$ timeout将确保在单个$ apply块中调用代码。
答案 6 :(得分:3)
在任何时间点,只能进行一次$digest
或$apply
操作。这是为了防止很难检测到进入您的应用程序的错误。此错误的堆栈跟踪允许您跟踪当前正在执行的$apply
或$digest
调用的来源,这会导致错误。
更多信息: https://docs.angularjs.org/error/$rootScope/inprog?p0=$apply
答案 7 :(得分:2)
刚刚解决了这个问题。它记载了here。
我在同一个流程中两次调用$rootScope.$apply
。我所做的就是用setTimeout(func, 1)
包装服务函数的内容。
答案 8 :(得分:1)
我知道它的旧问题,但如果你真的需要使用$ scope。$ applyAsync();
答案 9 :(得分:0)
我调用$ scope。$这样适用于忽略多次调用多次。
var callApplyTimeout = null;
function callApply(callback) {
if (!callback) callback = function () { };
if (callApplyTimeout) $timeout.cancel(callApplyTimeout);
callApplyTimeout = $timeout(function () {
callback();
$scope.$apply();
var d = new Date();
var m = d.getMilliseconds();
console.log('$scope.$apply(); call ' + d.toString() + ' ' + m);
}, 300);
}
只需致电
callApply();
答案 10 :(得分:0)
在这种情况下,我们可以使用setTimeout
函数。
console.log('primary task');
setTimeout(function() {
console.log('secondary task');
}, 0);
这将确保在完成主要任务时将执行次要任务。
答案 11 :(得分:0)
仅当 $apply
尚未进行时,您才可以 $apply
您的更改。您可以将代码更新为
if(!$scope.$$phase) $scope.$apply();