1. ホーム
  2. angularjs

[解決済み] if(!$scope.$$phase) $scope.$apply() の使用はなぜアンチパターンなのでしょうか?

2023-02-21 08:49:29

質問

時々、私は $scope.$apply を使用する必要がありますが、時々、"digest already in progress"というエラーがスローされます。そこで、これを回避する方法を探し始めたところ、この質問を見つけました。 AngularJS 。スコープを呼び出すときにエラー$digest already in progressを防ぐ.$apply() . しかし、コメントで(そしてangular wikiで)読むことができます。

if (!$scope.$$phase) $scope.$apply() はやめましょう。それは $scope.$apply() がコールスタックの中で十分に高くないことを意味します。

では、2つ質問させてください。

  1. なぜこれがアンチパターンなのでしょうか?
  2. どうすれば安全に$scope.$applyを使用できますか?

digest already in progress"エラーを防ぐための別の"ソリューション"は、$timeoutを使用するようです。

$timeout(function() {
  //...
});

これでいいのか?より安全なのでしょうか?では、ここからが本当の問題です。どうすれば はまったく すでに進行中のダイジェスト(digest in progress")エラーの可能性を排除できますか?

PS: 私は同期ではないangularjsのコールバックで$scope.$applyを使用しているだけです。(私の知る限り、それらは、変更を適用したい場合、$scope.$applyを使用しなければならない状況です)

どのように解決するのですか?

さらに調べていくと、この疑問は解決することができました。 $scope.$apply . 短い答えは「イエス」です。

長い答えです。

ブラウザがどのようにJavascriptを実行するかによって、2つのダイジェスト呼び出しが衝突することはありえません。 偶然 .

私たちが書く JavaScript のコードは、すべて一度に実行されるのではなく、順番に実行されます。各ターンは最初から最後まで途切れることなく実行され、ターンが実行されているときは、ブラウザでは他のことは何も起こりません。(以下 http://jimhoskins.com/2012/12/17/angularjs-and-apply.html )

したがって、エラー "digest already in progress" は、ある状況下でしか発生しません。ある$applyが別の$applyの内部で発行されたとき、などです。

$scope.apply(function() {
  // some code...
  $scope.apply(function() { ... });
});

この状況は ではない 生じる もし のコールバックのように、angularjs 以外の純粋なコールバックで $scope.apply を使用します。 setTimeout . ですから、次のコードは100%防弾で、そこには はありません。 を行う必要があります。 if (!$scope.$$phase) $scope.$apply()

setTimeout(function () {
    $scope.$apply(function () {
        $scope.message = "Timeout called!";
    });
}, 2000);

これでもか

$scope.$apply(function () {
    setTimeout(function () {
        $scope.$apply(function () {
            $scope.message = "Timeout called!";
        });
    }, 2000);
});

とは ではない は安全です (なぜなら $timeout は - 他の angularjs ヘルパーと同様に - すでに $scope.$apply を呼び出すからです)。

$timeout(function () {
    $scope.$apply(function () {
        $scope.message = "Timeout called!";
    });
}, 2000);

また、このことは if (!$scope.$$phase) $scope.$apply() がアンチパターンである理由もここにあります。もし、あなたが $scope.$apply を正しい方法で使うなら、必要ないだけです。のような純粋な js コールバックでは setTimeout のような純粋なjsコールバックで行います。

読む http://jimhoskins.com/2012/12/17/angularjs-and-apply.html をご覧ください。