$ apply已在进行中错误

时间:2013-09-05 00:46:09

标签: angularjs cordova angular-digest

堆栈追踪:

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上它抛出了上述错误。任何想法都错了吗?

12 个答案:

答案 0 :(得分:101)

您收到此错误是因为您在现有的消化周期内调用了$apply

最大的问题是:你为什么打电话给$apply?除非您从非Angular事件接口,否则您不应该呼叫$apply$apply的存在通常意味着我做错了(除非,$ apply适用于非Angular事件)。

如果此处$apply确实合适,请考虑使用“安全申请”方法:

https://coderwall.com/p/ngisma

答案 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();