AngularJS:$ scope。$ apply()を呼び出すときにすでに進行中のエラー$ digestを防止します


838

Angularでアプリケーションを構築してから、ページをスコープに手動で更新する必要があることがわかりました。

これを行うために知っている唯一の方法$apply()は、コントローラーとディレクティブのスコープから呼び出すことです。これの問題は、次のようなエラーがコンソールにスローされ続けることです。

エラー:$ digestはすでに進行中です

このエラーを回避する方法、または同じことを異なる方法で達成する方法を誰かが知っていますか?


34
$ applyをどんどん使用する必要があるのは本当にイライラすることです。
OZ_ 2013年

コールバックで$ applyを呼び出しているにもかかわらず、このエラーも発生しています。サードパーティのライブラリを使用してサーバーのデータにアクセスしているので、$ httpを利用できません。また、$ httpを使用するためにライブラリを書き換える必要があるため、利用したくありません。
Trevor

45
使用$timeout()
OnurYıldırım2014年

6
$ timeout(fn)+ 1を使用して問題を解決できます。!$ scope。$$ phaseは最適なソリューションではありません。
Huei Tan 2014

1
コード/呼び出しスコープのみをラップします。$ applyはタイムアウト($ timeoutではない)AJAX関数($ httpではない)およびイベント(ではない)から適用しますng-*。(timeout / ajax / eventsを介して呼び出される)関数内から呼び出す場合は、最初にロード時に実行されていないことを確認してください。
Patrick

回答:


660

このパターンは使用しないでください -解決するよりも多くのエラーが発生します。何かを修正したと思っていても、修正しませんでした。

をチェックすることで、a $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アンチパターン

  1. しないでくださいif (!$scope.$$phase) $scope.$apply()。これは$scope.$apply()、コールスタックで十分な高さになっていないことを意味します。

230
$ digest / $ applyはデフォルトでこれを行うべきだと私には
思える

21
場合によっては、現在のスコープとルートスコープだけをチェックする必要があることに注意してください。ルートで$$ phaseの値を取得していますが、スコープでは取得していません。ディレクティブの分離スコープと関係があると思いますが、..
Roy Truelove

106
やめるif (!$scope.$$phase) $scope.$apply()」、github.com
angular /

34
@anddoutoi:同意する; あなたがリンクしていることは、これが解決策ではないことを明確にします。ただし、「コールスタックであなたが十分に高くない」とはどういう意味かわかりません。これが何を意味するか知っていますか?
Trevor

13
@threed:aaronfrostの答えを見てください。正しい方法は、遅延を使用して次のサイクルでダイジェストをトリガーすることです。そうしないと、イベントが失われ、スコープがまったく更新されません。
Marek、

663

このトピックに関するAngularの人たちとの最近の議論から:将来を見据えた理由から、$$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のdelay引数はオプションであり、未設定のままにするとデフォルトで0になることに注意してください($ timeout$ browser.deferを呼び出します。、delayが設定されていない場合はデフォルトで0になります)。

少し直感的ではありませんが、それはAngularを書いている人たちからの答えなので、私には十分です!


5
私は私の指令でこれに何度も遭遇しました。redactorの1つを書いていたが、これは完全に機能することがわかった。私はBrad Greenとの会合で、JSのネイティブの監視機能を使用し、それを欠いているブラウザーにポリフィルを使用すると、ダイジェストサイクルがなくなるため、Angular 2.0は巨大になると彼は言った。この時点で、これを行う必要はありません。:)
マイケルJ.カルキンス2013年

昨日、$ timeout内で selectize.refreshItems()を呼び出すと、恐ろしい再帰的なダイジェストエラーが発生する問題を見ました。それがどのようになり得るかについてのアイデアはありますか?
iwein 2014年

3
$timeoutネイティブsetTimeoutではなく使用する場合$window、ネイティブの代わりに使用しないのはなぜwindowですか?
LeeGee 2016年

2
@LeeGee:$timeoutこの場合の使用のポイントは$timeout、角度スコープが適切に更新されるようにすることです。$ digestが進行中でない場合、新しい$ digestが実行されます。
2016年

2
@webicyそんなことはありません。$ timeoutに渡された関数の本体が実行されると、promiseはすでに解決されています!理由はまったくありませんcancel文書から:「この結果、約束は拒絶によって解決されます。」解決された約束を解決することはできません。キャンセルしてもエラーは発生しませんが、プラスになることはありません。
daemonexmachina 2018

324

ダイジェストサイクルは同期呼び出しです。完了するまで、ブラウザのイベントループに制御を委譲しません。これに対処するにはいくつかの方法があります。これに対処する最も簡単な方法は、組み込みの$ timeoutを使用することです。2番目の方法は、アンダースコアまたはロダッシュを使用している場合(そうでなければなりません)、次のように呼び出します。

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

またはロダッシュがある場合:

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

いくつかの回避策を試しましたが、すべてのコントローラー、ディレクティブ、さらにはいくつかのファクトリーに$ rootScopeを挿入することは嫌いでした。したがって、これまでのところ$ timeoutと_.deferが私たちのお気に入りです。これらのメソッドは、現在のscope。$ applyが終了することを保証する次のアニメーションループまで待機するようにangularに正常に指示します。


2
これは$ timeout(...)を使用することに相当しますか?私はいくつかのケースで$ timeoutを使用して次のイベントサイクルまで延期してきましたが、うまく機能しているようです-$ timeoutを使用しない理由があるかどうか誰かが知っていますか?
Trevor

9
これは本当にを既に使用している場合にのみ使用してくださいunderscore.js。このソリューションは、そのdefer関数を使用するためだけにアンダースコアライブラリ全体をインポートする価値はありません。他のライブラリに依存することなく、$timeout誰もが既に$timeoutAngular経由でアクセスできるため、私はこのソリューションを非常に好みます。
テニスジェント2014年

10
確かに...しかし、アンダースコアまたはロダッシュを使用していない場合は...何をしているかを再評価する必要があります。これら2つのライブラリは、コードの外観を変更しました。
凍えるような2014年

2
Restangularの依存関係としてlodashがあります(すぐにng-routeを支持してRestangularを削除します)。私はそれは良い答えだと思いますが、人々がアンダースコア/ロダッシュを使いたいと思うのは良くありません。どういうわけか、それらのライブラリは問題ありません...十分に活用しているのであれば...最近は、アンダースコア含めるために使用した理由の98%を消去するES5メソッドを使用しています。
BradGreens 2014年

2
あなたは正しい@SgtPookiです。$ timeoutを使用するオプションも含めるように答えを変更しました。$ timeoutと_.deferはどちらも次のアニメーションループまで待機します。これにより、現在のスコープが確実に終了します。$ applyが終了します。私を正直に保ち、ここで答えを更新してくれてありがとう。
凍りつく14年

267

ここでの回答の多くには良いアドバイスが含まれていますが、混乱を招く可能性もあります。単に使うので$timeoutない、最善でも適切な解決策でも。また、パフォーマンスやスケーラビリティが気になる場合は、必ずお読みください。

知っておくべきこと

  • $$phase フレームワークにプライベートであり、そのための十分な理由があります。

  • $timeout(callback)現在のダイジェストサイクル(存在する場合)が完了するまで待機し、コールバックを実行して、最後にfullを実行します$apply

  • $timeout(callback, delay, false)(コールバックを実行する前のオプションの遅延で)同じことを行い$applyますが、Angularモデル($ scope)を変更しなかった場合にパフォーマンスを節約する(3番目の引数)を起動しません。

  • $scope.$apply(callback)特にを呼び出します。$rootScope.$digestつまり、分離されたスコープ内にいる場合でも、アプリケーションのルートスコープとそのすべての子を再消化します。

  • $scope.$digest()は単にモデルをビューに同期しますが、親のスコープを消化しません。これにより、HTMLの分離された部分を(ほとんどディレクティブから)分離されたスコープで処理するときに多くのパフォーマンスを節約できます。$ 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アプリケーションの一部である分離された小さなディレクティブで何をしていて作業しているのかわかっている場合は、$ applyではなく$ digestを使用してパフォーマンスを節約できます。

Angularjs 1.2以降の更新

$ scopeに新しい強力なメソッドが追加されました: $evalAsync。基本的に、現在のダイジェストサイクルが発生している場合は、そのコールバックを実行します。それ以外の場合は、新しいダイジェストサイクルがコールバックの実行を開始します。

これは$scope.$digest、HTMLの分離された部分のみを同期する必要があることを本当に知っている場合($apply進行中のものがない場合に新しいものがトリガーされるため)ほど優れていませんが、これは関数を実行しているときの最良の解決策ですこれは、同期またはないで実行する場合は、あなたがそれを知ることができない潜在的にキャッシュされたリソースを取得した後、たとえば、:時々これは、サーバへの非同期呼び出しが必要になりますそれ以外の場合は、リソースがローカルに同期フェッチされます。

これらの場合、およびがあった他のすべての場合は、!$scope.$$phase必ず使用してください$scope.$evalAsync( callback )


4
$timeoutついでに批評されます。回避する理由をもっと教えてもらえます$timeoutか?
mlhDev 2017年

88

このプロセスをDRYに保つための便利な小さなヘルパーメソッド:

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

6
safeApplyは、何が起こっているのかを何よりも理解するのに役立ちました。投稿いただきありがとうございます。
Jason More

4
私も同じことをやろうとしていましたが、fn()で行った変更が$ digestに表示されない可能性があるという意味ではありませんか?scope。$$ phase === '$ digest'を想定して、関数を遅延させる方が良いでしょうか?
Spencer Alger 2013

$ apply()を使用してダイジェストをトリガーし、fnを単独で呼び出すだけで問題が発生することはありませんか。
CMCDragonkai 2013

1
私はのように感じる scope.$apply(fn);べきであるscope.$apply(fn());FN()は、FN機能を実行しないので。私が間違っているところまで助けてください
madhu131313 '25 / 07/25

1
@ZenOut $ applyの呼び出しは、関数を含むさまざまな種類の引数をサポートします。関数を渡すと、関数を評価します。
boxmein

33

たとえば、CodeMirrorやKrpanoなどのサードパーティのスクリプトでも同じ問題が発生しました。ここで説明したsafeApplyメソッドを使用しても、エラーは解決しませんでした。

しかし、それを解決したのは$ timeoutサービスを使用することです(最初に注入することを忘れないでください)。

したがって、次のようなもの:

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

コード内で使用している場合

この

おそらくそれがファクトリディレクティブのコントローラ内にあるか、何らかのバインディングが必要なためか、次のようにします。

.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();

  }]
)

32

見る http://docs.angularjs.org/error/$rootScope:inprogを

この問題は$apply、Angularコードの外部で非同期に実行され($ applyを使用する必要がある場合)、Angularコードの内部で同期的に実行される(これにより、$digest already in progressエラーの)にます。

これは、たとえば、サーバーからアイテムを非同期でフェッチしてキャッシュするライブラリがある場合に発生する可能性があります。アイテムが初めてリクエストされたとき、コードの実行をブロックしないように非同期で取得されます。ただし、2回目は、アイテムは既にキャッシュにあるため、同期して取得できます。

このエラーを防ぐ方法は、呼び出すコードが$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...

電話するだけ $apply実行中のコードが常にAngularコードの外部で実行されることがわかっている場合にます(たとえば、$ applyの呼び出しは、Angularコードの外部のコードによって呼び出されるコールバック内で発生します)。

$timeoutover を使用することによる影響があるデメリットに気付いていない限り、ほぼ同じことを行うため、の代わりに(遅延なしで)を$apply常に使用できない理由はわかりません。$timeout$apply


おかげで、これは$apply自分に電話をかけていなくてもエラーが発生する私の場合にはうまくいきました。
ariscris

5
主な違いは、$apply同期している(コールバックが実行され、次に$ applyに続くコード)が同期され$timeoutないことです。タイムアウトに続く現在のコードが実行され、新しいスタックは、を使用しているかのようにそのコールバックで始まりますsetTimeout。同じモデルを2回更新すると、グラフィックに問題が発生する可能性があります$timeout。ビューが更新されるのを待ってから、再度更新します。
floribon 2014年

本当にありがとうございます。$ watchアクティビティの結果として呼び出されるメソッドがあり、外部フィルターの実行が完了する前にUIを更新しようとしていました。これを$ timeout関数の中に入れるとうまくいきました。
djmarquette 2014

28

このエラーが発生した場合、基本的には、ビューの更新処理がすでに進行中であることを意味します。$apply()コントローラー内で呼び出す必要はありません。ビューが期待どおりに更新されず、を呼び出した後にこのエラーが発生$apply()する場合は、モデルを正しく更新していない可能性があります。具体的な内容を投稿していただければ、問題の核心を突き止めることができます。


えーと、AngularJSは "魔法のように"バインディングを監視できないので、$ apply()で時々プッシュする必要があることを知るために丸一日費やしました。
OZ_ 2013年

どういう意味you're not updating the the model correctlyですか?$scope.err_message = 'err message';正しいアップデートではありませんか?
OZ_ 2013年

2
呼び出す必要があるの$apply()は、angularの「外部」でモデルを更新するときだけです(たとえば、jQueryプラグインから)。ビューが正しく見えないという罠に陥りやすいので、$apply()どこにでもsをたくさん投げると、OPでエラーが発生します。私が言うときはyou're not updating the the model correctly、すべてのビジネスロジックがスコープ内にある可能性のあるものを正しく入力していないことを意味します。これにより、ビューが期待どおりに表示されなくなります。
dnc253 2013年

@ dnc253私は同意し、私は答えを書きました。今知っていることを知っているので、$ timeout(function(){...});を使用します。_.deferと同じことを行います。どちらも次のアニメーションループに従います。
凍りつく14年


11

evalAsyncを使用することもできます。ダイジェストが終了した後、いつか実行されます!

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

10

まず、この方法で修正しないでください

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! 
});

アンダースコアまたはロダッシュを使用している場合は、defer()を使用できます。

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

9

この方法を使用すると、エラーが発生する場合があります(https://stackoverflow.com/a/12859093/801426)。

これを試して:

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

5
!$ scope。$$ phaseと!$ scope。$ root。$$ phase(!$ rootScope。$ root。$$ phaseではない)の両方を使用するとうまくいきます。+1
asprotte 2013年

2
$rootScopeanyScope.$root同じ男です。$rootScope.$root冗長です。
floribon 2015


5

使ってみる

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

の代わりに

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

$ applyAsync $ applyの呼び出しが後で発生するようにスケジュールします。これは、同じダイジェストで評価する必要がある複数の式をキューに入れるために使用できます。

注:$ digest内で、$ applyAsync()は、現在のスコープが$ rootScopeである場合にのみフラッシュします。つまり、子スコープで$ digestを呼び出しても、$ applyAsync()キューは暗黙的にフラッシュされません。

例:

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

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

参照:

1. AngularJS 1.3でのScope。$ applyAsync()とScope。$ evalAsync()の比較

  1. AngularJsドキュメント

4

ダイジェストサイクルをトリガーするのではなく、カスタムイベントを使用することをお勧めします。

カスタムイベントをブロードキャストし、このイベントのリスナーを登録することは、ダイジェストサイクルであるかどうかに関係なく、発生させたいアクションをトリガーするための優れたソリューションであることがわかりました。

カスタムイベントを作成することにより、コードでより効率的になります。これは、そのイベントにサブスクライブされたリスナーのみをトリガーし、scope。$ applyを呼び出した場合のようにスコープにバインドされたすべてのウォッチをトリガーしないためです。

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


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

3

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);

2

この問題は、関数が実行されることがわかっている場所では$evalなく、$applyを呼び出すことで解決できました$digest

docsによると、$apply基本的にこれを行います:

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

私の場合、ng-clickはスコープ内の変数を変更し、その変数の$ watchはでなければならない他の変数を変更します$applied。この最後のステップにより、「ダイジェストはすでに進行中」というエラーが発生します。

置き換えることによって$apply$evalウォッチ式の内側にスコープ変数は、予想通り更新されます。

そのため、表示されたダイジェストが原因角度内の他のいくつかの変更をとにかく実行していることが起こっている場合は、その$eval「INGは、すべてを行う必要があります。



1

Angularのドキュメントがアンチパターンをチェックする$$phaseことを要求していることを理解して、私は取得して動作しようとしました。$timeout_.defer

timeoutメソッドとdeferredメソッド{{myVar}}FOUTのように、DOMに解析されていないコンテンツのフラッシュを作成します。私にはこれは受け入れられませんでした。何かがハックであり、適切な代替手段がないことを独断的に教えられることはあまりありません。

毎回機能する唯一のものは次のとおりです。

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

私はこの方法の危険性、またはコメントや角張ったチームで人々によってハッキングとして説明されている理由を理解していません。コマンドは正確で読みやすいようです:

「すでに起こっていない限り、ダイジェストを行う」

CoffeeScriptではさらにきれいです。

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

これの問題は何ですか?FOUTを作成しない代替手段はありますか?$ safeApply正常に見えますが、$$phase検査方法も使用します。


1
この質問に対する情報に基づいた回答を見たいです。
ベンウィーラー

これはハックです。これは、この時点でコンテキストを見逃したり、コードを理解できなかったりすることを意味します。角度ダイジェストサイクル内にいて、それを必要としないか、非同期でその外側にいて、それを必要とするためです。コードのその時点でそれがわからない場合は、コードを消化する責任はありません
floribon

1

これは私の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']);
};

1

私はこの方法を使用しており、完全に問題なく動作するようです。これは、サイクルが終了するまで待機してからトリガーします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);
  }
}

1

デバッガーを無効にすると、エラーは発生しなくなりました。私の場合、それはデバッガがコード実行を停止したことが原因でした。


0

上記の回答に似ていますが、これは私にとって忠実に機能しました...サービスの追加:

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

0

使用できます

$timeout

エラーを防ぐために。

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

$ timeoutを使いたくない場合
rahim.nagori

0

問題が発生しているのは、ダイジェストサイクルを実行するために角度を要求しているときです。ただし、そのプロセスが理解のために問題を引き起こしています。コンソールの結果例外。
1. $ timeout関数内でscope。$ apply()を呼び出すことは、内部的には同じであるため、意味がありません。
2.ネイティブではない角度が定義されているため、コードはバニラJavaScript関数に対応
しています。つまり、setTimeout 3.

if(!scope。$$ phase){
scope。$ evalAsync(function(){

});を使用できます。}


0
        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();
        });

-3

これを見つけました:https : //coderwall.com/p/ngismaここでNathan Walker(ページの下部近く)はfunc 'safeApply'を作成するために$ rootScopeのデコレーターを提案しています、コード:

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

-7

これはあなたの問題を解決します:

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

(!$ scope。$$ phase)$ scope。$ apply()の場合は行わないでください。これは、$ scope。$ apply()がコールスタックで十分に高くないことを意味します。
MGot90
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.