我发现由于需要在angular中构建应用程序,因此我需要越来越多地手动将页面更新到我的范围。

,我唯一知道的方法是从的范围中调用$apply()我的控制器和指令。问题是它不断向显示以下内容的控制台抛出错误:


错误:$ digest已在进行中


有人吗?知道如何避免该错误或以不同的方式实现相同的结果?

评论

我们需要越来越多地使用$ apply,这真是令人沮丧。

即使在回调中调用$ apply,我也收到此错误。我正在使用第三方库来访问其服务器上的数据,所以我无法利用$ http,也不想这样做,因为我必须重写其库才能使用$ http。

使用$ timeout()

使用$ timeout(fn)+ 1,它可以解决问题!$ scope。$$ phase不是最佳解决方案。

仅包装代码/调用范围。$在超时(不是$ timeout)内应用AJAX函数(不是$ http)和事件(不是ng- *)。确保,如果要从一个函数中调用它(通过timeout / ajax / events调用),请确保它最初也不在加载时运行。

#1 楼


不要使用此模式-最终将导致更多错误而不是其解决。即使您认为它可以修复某些问题,也没有。


您可以通过检查$digest来检查$scope.$$phase是否已经在进行中。

if(!$scope.$$phase) {
  //$digest or $apply
}


如果正在进行$scope.$$phase"$digest",则"$apply"将返回$digest$apply。我相信这两种状态之间的区别在于,$digest将处理当前范围及其子级的手表,而$apply将处理所有范围的手表。

@ dnc253的意思是,如果您发现自己打电话给$digest$apply经常出现,您可能做错了。通常,由于Angular无法触发DOM事件而需要更新作用域的状态时,我通常需要摘要。例如,当一个Twitter引导模态被隐藏时。有时,在进行$digest时会触发DOM事件,有时则不会。这就是为什么我使用这张支票。

如果有人认识我,我想知道一种更好的方法。


来自评论:@anddoutoi的



angular.js反模式



不要执行if (!$scope.$$phase) $scope.$apply(),这意味着您的$scope.$apply()在调用堆栈中不够高。



评论


在我看来,$ digest / $ apply应该默认执行此操作

–罗伊·特雷洛夫(Roy Truelove)
13年1月11日在20:12

请注意,在某些情况下,我必须检查当前范围和根范围。我已经在根目录上获得了$$ phase的值,但在我的示波器上却没有。认为它与指令的隔离范围有关,但是..

–罗伊·特雷洛夫(Roy Truelove)
2013年1月14日15:33

“停止执行if(!$ scope。$$ phase)$ scope。$ apply()”,github.com/angular/angular.js/wiki/Anti-Patterns

– anddoutoi
2013年9月5日上午8:56

@anddoutoi:同意;您的链接非常清楚,这不是解决方案;但是,我不确定“您在调用堆栈中不够高”的含义。你知道这是什么意思吗?

–特雷弗
13年13月13日在19:19

@threed:请参见aaronfrost的答案。正确的方法是使用defer在下一个周期中触发摘要。否则,事件将丢失并且根本不会更新范围。

–马雷克
2013年12月11日上午9:45

#2 楼

来自与Angular成员最近就此主题进行的讨论:出于面向未来的原因,您不应该使用$$phase

当按“正确”的方法进行操作时,答案是当前

$timeout(function() {
  // anything you want can go here and will safely be run on the next digest.
})


我最近在编写有角度的服务来包装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的delay参数是可选的,如果未设置则默认为0($ timeout调用$ browser.defer,如果未设置delay则默认为0)

有点不直观,但这就是编写Angular的人的答案,所以对我来说已经足够了!

评论


我在指令中遇到了很多次。正在为编剧编写一个,事实证明它可以完美工作。我在与Brad Green的一次聚会中,他说Angular 2.0将会非常强大,并且没有使用JS的本机观察功能并为缺少该功能的浏览器使用polyfill的摘要周期。届时,我们将不再需要这样做。 :)

–迈克尔·J·卡尔金斯(Michael J. Calkins)
13年10月10日在21:13

昨天我看到了一个问题,其中在$ timeout中调用selectize.refreshItems()导致了可怕的递归摘要错误。任何想法怎么可能?

– iwein
2014年3月12日在6:02

如果您使用$ timeout而不是本机setTimeout,为什么不使用$ window而不是本机窗口?

–LeeGee
16 Jan 27'在10:24

@LeeGee:在这种情况下使用$ timeout的要点是$ timeout确保正确地更新了角度范围。如果$ digest不在进行中,它将导致新的$ digest运行。

–敬畏
16年5月10日在8:50

@webicy没什么。当传递给$ timeout的函数主体运行时,promise已经解决!绝对没有理由取消它。来自文档:“因此,诺言将被拒绝解决。”您无法解决已解决的承诺。您的取消不会导致任何错误,但也不会做任何积极的事情。

–daemonexmachina
18年2月5日在10:30

#3 楼

摘要周期是一个同步调用。在完成之前,它不会控制浏览器的事件循环。有几种方法可以解决这个问题。解决此问题的最简单方法是使用内置的$ timeout,第二种方法是如果使用下划线或lodash(应该这样),请调用以下命令:

$timeout(function(){
    //any code in here will automatically have an apply run afterwards
});


,或者如果您有破折号:

_.defer(function(){$scope.$apply();});


我们尝试了几种解决方法,并且我们讨厌将$ rootScope注入到我们所有的控制器,指令甚至一些工厂。因此,到目前为止,$ timeout和_.defer是我们最喜欢的。这些方法成功地告诉angular等待下一个动画循环,这将确保当前scope。$ apply已经结束。

评论


这相当于使用$ timeout(...)吗?我已经在几种情况下使用$ timeout推迟到下一个事件周期,而且看起来工作正常-有人知道是否有理由不使用$ timeout吗?

–特雷弗
2013年12月11日20:46

仅当您已经在使用underscore.js时,才应使用此选项。仅使用其defer函数,此解决方案就不值得导入整个下划线库。我非常喜欢$ timeout解决方案,因为每个人都可以通过angular访问$ timeout,而无需依赖其他库。

–网球
2014年1月8日19:22

是的,但是如果您不使用下划线或破折号,则需要重新评估您的工作。这两个库改变了代码的外观。

–霜冻
2014年1月8日在22:48

我们将lodash作为Restangular的依赖项(我们将尽快消除Restangular以便​​使用ng-route)。我认为这是一个很好的答案,但是假设人们想使用下划线/破折号并不是很好。不管怎么说,这些库都很好...如果您充分利用它们...这些天,我使用ES5方法消除了我以前使用下划线的98%的原因。

– BradGreens
2014年5月1日19:30



您说对了@SgtPooki。我修改了答案,以包括也可以使用$ timeout的选项。 $ timeout和_.defer都将等到下一个动画循环,这将确保当前范围。$ apply已结束。感谢您保持诚实,并让我在此处更新答案。

–霜冻
2014年6月17日15:12

#4 楼

这里的许多答案都包含很好的建议,但也可能导致混乱。简单地使用$timeout既不是最佳解决方案,也不是正确的解决方案。
此外,如果您对性能或可伸缩性感到担忧,请务必阅读。

您应该了解的事情


$$phase是框架专用的,有充分的理由。
$timeout(callback)将等待直到当前摘要周期(如果有)完成,然后执行回调,然后在最后运行完整的$apply
$timeout(callback, delay, false)将执行相同的操作(在执行回调之前具有可选的延迟),但不会触发$apply(第三个参数),如果您不修改Angular模型($ scope),则可以节省性能。
$scope.$apply(callback)会调用$rootScope.$digest等,这意味着即使您处于隔离范围内,它也会重新分配应用程序及其所有子级的根范围。
$scope.$digest()只会同步其模型可以看到,但不会消化其父级范围,在处理HT的孤立部分时可以节省很多性能具有隔离范围的ML(主要来自指令)。 $ digest不会进行回调:执行代码,然后进行摘要。
$scope.$evalAsync(callback)已在angularjs 1.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);
});


而且,如果您知道自己在做什么,并且正在作为大型Angular应用程序的一部分使用一个孤立的小指令,则可以使用$ digest而不是$ apply来节省性能。

自Angularjs 1.2起进行更新

新的,功能强大的方法已添加到任何$ scope:$evalAsync。基本上,如果发生,它将在当前摘要周期内执行其回调,否则将以新的摘要周期开始执行该回调。

如果您真的知道,那还是不如$scope.$digest您只需要同步HTML的隔离部分(因为如果没有新的$apply将会被触发,则这将被触发),但是这是执行函数时不知道是否同步执行的最佳解决方案,例如,在获取可能缓存的资源后:有时需要异步调用服务器,否则资源将在本地同步获取。

在这些情况下,以及所有其他您拥有!$scope.$$phase ,请务必使用$scope.$evalAsync( callback )

评论


$ timeout在传递中受到批评。您能否给出更多避免$ timeout的理由?

– mlhDev
17年5月3日在21:08

#5 楼

方便的小助手方法来保持此过程干燥:

function safeApply(scope, fn) {
    (scope.$$phase || scope.$root.$$phase) ? fn() : scope.$apply(fn);
}


评论


您的safeApply帮助我了解正在发生的事情比什么都重要。感谢您发布。

–Jason More
13年6月20日在21:55

我将要做同样的事情,但这不是意味着$ digest有可能看不到我们在fn()中所做的更改吗?假设作用域延迟了函数会更好吗?$$ phase ==='$ digest'吗?

– Spencer Alger
2013年9月10日0:16



我同意,有时$ apply()用于触发摘要,仅通过本身调用fn ...不会导致问题吗?

– CMCDragonkai
2013年9月17日下午3:02

我感觉像范围。$ apply(fn);应该是scope。$ apply(fn());因为fn()将执行函数而不是fn。请帮助我到哪里我错了

– Madhu131313
15年7月25日在15:00

@ZenOut对$ apply的调用支持许多不同种类的参数,包括函数。如果传递了函数,它将评估该函数。

– boxmein
16-4-7在14:33



#6 楼

我对第三方脚本(例如CodeMirror和Krpano)有同样的问题,
甚至使用此处提到的safeApply方法都无法解决我的错误。

但是解决了什么问题正在使用$ timeout服务(请不要忘记先注入它)。

因此,类似:

$timeout(function() {
  // run my code safely here
})


,如果在您的内部您正在使用的代码


this


也许是因为它在工厂指令的控制器内,或者只需要某种绑定,那么您可能会做一些事情像:

.factory('myClass', [
  '$timeout',
  function($timeout) {

    var myClass = function() {};

    myClass.prototype.surprise = function() {
      // Do something suprising! :D
    };

    myClass.prototype.beAmazing = function() {
      // Here 'this' referes to the current instance of myClass

      $timeout(angular.bind(this, function() {
          // Run my code safely here and this is not undefined but
          // the same as outside of this anonymous function
          this.surprise();
       }));
    }

    return new myClass();

  }]
)


#7 楼

请参阅http://docs.angularjs.org/error/$rootScope:inprog

当您调用$apply有时在Angular代码之外异步运行时,会出现问题(当$ apply应该是有时在Angular代码中同步使用(这会导致$digest already in progress错误)。

例如,当您有一个库可以从服务器异步获取项并缓存它们时,可能会发生这种情况。第一次请求项目时,将异步检索该项目,以免阻止代码执行。但是,第二次,该项目已经在缓存中,因此可以同步检索。

防止此错误的方法是确保调用$apply的代码异步运行。这可以通过在对$timeout的调用中运行代码并将延迟设置为0(默认设置)来完成。但是,在$timeout内部调用代码消除了调用$apply的必要性,因为$ timeout会自行触发另一个$digest循环,这反过来又会进行所有必要的更新等。

解决方案

简而言之,不要这样做:

... your controller code...

$http.get('some/url', function(data){
    $scope.$apply(function(){
        $scope.mydate = data.mydata;
    });
});

... more of your controller code...


请这样做:

... your controller code...

$http.get('some/url', function(data){
    $timeout(function(){
        $scope.mydate = data.mydata;
    });
});

... more of your controller code...


仅当知道运行它的代码将始终在Angular代码外部运行时才调用$apply(例如,对$ apply的调用将在Angular代码外部的代码调用的回调中发生)。

除非有人意识到使用$timeout而不是$apply会带来一些不利的影响,但我不明白为什么不能总是使用$timeout(零延迟)代替$apply,因为这样做的效果大致相同。

评论


谢谢,这对于我不调用$ apply但仍然出现错误的情况很有用。

–ariscris
2014年10月10日14:51

主要区别在于$ apply是同步的(执行其回调,然后执行$ apply之后的代码),而$ timeout则不是:执行超时后的当前代码,然后一个新的堆栈以其回调开始,就像您正在使用setTimeout 。如果您要更新两次相同的模型,可能会导致图形故障:$ timeout将等待刷新视图,然后再次更新。

– floribon
2014年6月1日在21:20



的确,谢谢。由于某些$ watch活动,我有一个方法被调用,并且在我的外部过滤器执行完之前试图更新UI。将其放入$ timeout函数对我来说很有效。

– djmarquette
2014年7月17日14:56

#8 楼

当您收到此错误时,基本上意味着它已经在更新视图。您确实不需要在控制器内调用$apply()。如果您的视图没有按预期更新,然后在调用$apply()后收到此错误,则很可能表示您没有正确更新模型。如果您发布一些细节,我们可以找出核心问题。

评论


呵呵,我花了一整天的时间发现AngularJS不能“神奇地”观察绑定,有时我应该用$ apply()来推动他。

– OZ_
13年5月20日在22:10



到底意味着您没有正确更新模型? $ scope.err_message ='错误消息';是不正确的更新?

– OZ_
13年5月20日在22:12

唯一需要调用$ apply()的时间是在更新angular模型的“外部”时(例如,从jQuery插件中获取)。很容易陷入视图不正确的陷阱,因此您到处都抛出了一堆$ apply(),这最终导致在OP中看到错误。当我说您没有正确更新模型时,我的意思是所有业务逻辑都没有正确填充范围中可能包含的所有内容,这将导致视图看起来不符合预期。

– dnc253
13年5月21日在16:14

@ dnc253我同意,我写下了答案。知道了我现在所知道的,我将使用$ timeout(function(){...});它的作用与_.defer相同。它们都遵循下一个动画循环。

–霜冻
2014年6月17日15:00

#9 楼

安全$apply的最短形式为:

$timeout(angular.noop)


#10 楼

您也可以使用evalAsync。它会在摘要完成后的某个时间运行!

scope.evalAsync(function(scope){
    //use the scope...
});


#11 楼

首先,不要以这种方式修复它

if ( ! $scope.$$phase) { 
  $scope.$apply(); 
}


这没有任何意义,因为$ phase只是$ digest周期的布尔标志,因此您的$ apply()有时不会运行。请记住,这是一种不好的做法。

相反,请使用$timeout

    $timeout(function(){ 
  // Any code in here will automatically have an $scope.apply() run afterwards 
$scope.myvar = newValue; 
  // And it just works! 
});


如果使用下划线或lodash,则可以使用defer() :

_.defer(function(){ 
  $scope.$apply(); 
});


#12 楼

如果使用这种方式,有时您仍然会出错(https://stackoverflow.com/a/12859093/801426)。

请尝试以下操作:

if(! $rootScope.$root.$$phase) {
...


评论


同时使用!$ scope。$$ phase和!$ scope。$ root。$$ phase(不是!$ rootScope。$ root。$$ phase)对我有用。 +1

– asprotte
13年5月29日在9:14

$ rootScope和anyScope。$ root是同一个人。 $ rootScope。$ root是多余的。

– floribon
15年4月30日在21:42

#13 楼

您应该根据上下文使用$ evalAsync或$ timeout。

这是一个带有很好解释的链接:


http://www.bennadel。 com / blog / 2605-scope-evalasync-vs-timeout-in-angularjs.htm


#14 楼

尝试使用

$scope.applyAsync(function() {
    // your code
});


,而不是

if(!$scope.$$phase) {
  //$digest or $apply
}


$ applyAsync调度$ apply的调用发生在晚点。这可用于排队多个需要在同一摘要中求值的表达式。

注意:在$ digest中,仅当当前作用域为$ rootScope时,$ applyAsync()才会刷新。这意味着,如果您在子作用域上调用$ digest,则不会隐式刷新$ applyAsync()队列。

示例:

  $scope.$applyAsync(function () {
                if (!authService.authenticated) {
                    return;
                }

                if (vm.file !== null) {
                    loadService.setState(SignWizardStates.SIGN);
                } else {
                    loadService.setState(SignWizardStates.UPLOAD_FILE);
                }
            });


参考文献:

AngularJS 1.3中的1.Scope。$ applyAsync()与Scope。$ evalAsync()对比


AngularJs Docs


#15 楼

我建议您使用自定义事件,而不要触发摘要周期。

我发现广播自定义事件并为此事件注册侦听器是触发所需动作的好方法无论您是否处于摘要循环中,都会发生。

通过创建自定义事件,您还可以更高效地使用代码,因为您仅触发订阅该事件的侦听器,而不像调用范围那样触发所有绑定到范围的监视。适用。

$scope.$on('customEventName', function (optionalCustomEventArguments) {
   //TODO: Respond to event
});


$scope.$broadcast('customEventName', optionalCustomEventArguments);


#16 楼

yearofmoo在为我们创建可重用的$ safeApply函数方面做得很好:


https://github.com/yearofmoo/AngularJS-Scope.SafeApply


用法:

//use by itself
$scope.$safeApply();

//tell it which scope to update
$scope.$safeApply($scope);
$scope.$safeApply($anotherScope);

//pass in an update function that gets called when the digest is going on...
$scope.$safeApply(function() {

});

//pass in both a scope and a function
$scope.$safeApply($anotherScope,function() {

});

//call it on the rootScope
$rootScope.$safeApply();
$rootScope.$safeApply($rootScope);
$rootScope.$safeApply($scope);
$rootScope.$safeApply($scope, fn);
$rootScope.$safeApply(fn);


#17 楼

我已经能够通过在我知道$eval函数将要运行的地方调用$apply而不是$digest来解决此问题。

根据文档,$apply基本上可以做到这一点:

function $apply(expr) {
  try {
    return $eval(expr);
  } catch (e) {
    $exceptionHandler(e);
  } finally {
    $root.$digest();
  }
}


对于我来说,ng-click会更改范围内的变量,而对该变量的$ watch会更改其他必须为$applied的变量。这最后一步导致错误“消化已在进行中”。

通过在监视表达式内用$apply替换$eval,范围变量将按预期更新。

因此,它出现如果由于Angular内的一些其他更改而使摘要仍在运行,那么您只需要做$eval'。

#18 楼

请改用$scope.$$phase || $scope.$apply();

#19 楼

了解到Angular文档要求检查$$phase是反模式后,我尝试使$timeout_.defer正常工作。

超时和延迟方法在dom中像FOUT一样闪烁了未解析的{{myVar}}内容。 。对我来说,这是不可接受的。这让我无需过多地从教条上得知某物是骇客,并且没有合适的替代品。

每次唯一起作用的是:

if(scope.$$phase !== '$digest'){ scope.$digest() }

我不了解这种方法的危险性,也不知道为什么人们在评论和有角度的团队中将其描述为骇客。该命令似乎准确且易于阅读:


“除非已发生摘要,否则请进行摘要”


在CoffeeScript中,它甚至更漂亮:

scope.$digest() unless scope.$$phase is '$digest'

这是什么问题?是否有不会创建FOUT的替代方案? $ safeApply看起来不错,但也使用$$phase检查方法。

评论


我希望看到对此问题的有见地的回答!

–本·惠勒
2014-09-22 15:41

这是骇客,因为这意味着您错过了上下文或在这一点上不了解代码:要么您处于角度摘要循环之内,并且您不需要它,要么异步地脱离了它,然后就需要了它。如果您不知道那段代码,则没有责任对其进行摘要

– floribon
15年4月30日在21:46

#20 楼

这是我的效用服务:

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']);
};


#21 楼

我一直在使用这种方法,它似乎工作得很好。这只是等待周期结束的时间,然后触发apply()。只需在任意位置调用函数apply(<your scope>)

function apply(scope) {
  if (!scope.$$phase && !scope.$root.$$phase) {
    scope.$apply();
    console.log("Scope Apply Done !!");
  } 
  else {
    console.log("Scheduling Apply after 200ms digest cycle already in progress");
    setTimeout(function() {
        apply(scope)
    }, 200);
  }
}


#22 楼

当我禁用调试器时,该错误不再发生。就我而言,这是因为调试器停止了代码执行。

#23 楼

与上面的答案类似,但是对我来说是忠实的...
服务中添加:

    //sometimes you need to refresh scope, use this to prevent conflict
    this.applyAsNeeded = function (scope) {
        if (!scope.$$phase) {
            scope.$apply();
        }
    };


#24 楼

您可以使用


$timeout


防止该错误。

 $timeout(function () {
                        var scope = angular.element($("#myController")).scope();
                        scope.myMethod();
                        scope.$scope();
                    },1);


评论


如果我不想使用$ timeout怎么办

–rahim.nagori
19年5月21日在7:39

#25 楼

当我们要求有角度地运行摘要循环时,这个问题基本上就来了,尽管它的过程正在造成对角度的理解上的问题。控制台中的后果异常。
1。在$ timeout函数中调用scope。$ apply()没有任何意义,因为在内部它会执行相同的操作。
2。该代码具有香草JavaScript函数,因为它的本机不是按角度定义的,即setTimeout
3。为此,您可以使用if(!scope。$$ phase){
scope。$ evalAsync(function(){});
}

#26 楼

        let $timeoutPromise = null;
        $timeout.cancel($timeoutPromise);
        $timeoutPromise = $timeout(() => {
            $scope.$digest();
        }, 0, false);


这是避免此错误并避免$ apply

的很好的解决方案,如果基于外部事件进行调用,则可以将其与debounce(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();
        });


#27 楼

发现了这一点:https://coderwall.com/p/ngisma,其中Nathan Walker(在页面底部附近)建议在$ rootScope中使用装饰器来创建func'safeApply',代码:

yourAwesomeModule.config([
  '$provide', function($provide) {
    return $provide.decorator('$rootScope', [
      '$delegate', function($delegate) {
        $delegate.safeApply = function(fn) {
          var phase = $delegate.$$phase;
          if (phase === "$apply" || phase === "$digest") {
            if (fn && typeof fn === 'function') {
              fn();
            }
          } else {
            $delegate.$apply(fn);
          }
        };
        return $delegate;
      }
    ]);
  }
]);


#28 楼

这将解决您的问题:

if(!$scope.$$phase) {
  //TODO
}


评论


如果(!$ scope。$$ phase)$ scope。$ apply()不这样做,则意味着您的$ scope。$ apply()在调用堆栈中不够高。

–MGot90
15年5月13日在15:28