web-dev-qa-db-ja.com

Angular $ scope。$ apply vs $ timeout as a safe $ apply

私は、Angularを一種の「安全な$ apply」メソッドとして$ timeoutサービスを使用することのニュアンスをよりよく理解しようとしています。基本的に、コードの一部がAngularイベントまたはjQueryや標準のDOMイベントなどの非角形イベントのいずれか。

私が物事を理解しているように:

  1. $ scope。$ applyでのコードのラップは、ダイジェストループ(別名jQueryイベント)にまだ入っていないシナリオでは正常に機能しますが、ダイジェストが進行中の場合はエラーが発生します
  2. 遅延パラメーターのない$ timeout()呼び出しでコードをラップすると、すでにダイジェストサイクルにあるかどうかに関係なく機能します。

Angularソースコードを見ると、$ timeoutが$ rootScope。$ apply()を呼び出しているように見えます。

  1. ダイジェストサイクルが既に進行中の場合、$ timeout()もエラーを発生させないのはなぜですか?
  2. ダイジェストがまだ進行中でないことが確実にわかっている場合は$ scope。$ apply()を使用し、どちらにしても安全である必要がある場合は$ timeout()を使用するのがベストプラクティスですか?
  3. $ timeout()は本当に許容できる「安全な適用」ですか、それとも落とし穴がありますか?

洞察力をありがとう。

68
bingles

Angularソースコードを見ると、$ timeoutが$ rootScope。$ apply()を呼び出しているようです。

  • ダイジェストサイクルが既に進行中の場合、$ timeout()もエラーを発生させないのはなぜですか?

$timeoutは、文書化されていないAngularサービス$browserを使用します。具体的には、$browser.defer()を使用して、関数の実行をwindow.setTimeout(fn, delay)を介して非同期に延期します。これは常にAngularライフサイクルの外側で実行されます。 window.setTimeoutが一度起動すると、関数は$timeout$rootScope.$apply()を呼び出します。

  • ダイジェストがまだ進行中でないことが確実にわかっている場合は$ scope。$ apply()を使用し、どちらにしても安全である必要がある場合は$ timeout()を使用するのがベストプラクティスですか?

そう言うでしょう。別の使用例として、ダイジェスト後にのみ初期化されることがわかっている$ scope変数にアクセスする必要がある場合があります。シンプルな例は、コントローラーのコンストラクター内でフォームの状態をダーティに設定する場合です(何らかの理由で)。 $ timeoutがなければ、FormControllerは初期化されず、$ scopeに公開されていないため、$scope.yourform.setDirty()を$ timeout内にラップすると、FormControllerが初期化されます。確かに、$ timeoutを使用せずにディレクティブを使用してこれらすべてを実行できます。別のユースケースの例を示します。

  • $ timeout()は本当に許容できる「安全な適用」ですか、それとも落とし穴がありますか?

常に安全である必要がありますが、あなたのgo toメソッドは常に私の意見では$ apply()を目指すべきです。私が取り組んでいる現在のAngularアプリはかなり大きく、$ apply()の代わりに1回だけ$ timeoutに依存する必要がありました。

61
Beyers

アプリケーションで$ applyを頻繁に使用すると、エラー:$ digestが既に進行中になる場合があります。一度に1つの$ digestサイクルを実行できるためです。 $ timeoutまたは$ evalAsyncで解決できます。

$ timeoutは、「$ digest already in progress」のようなエラーを生成しません。$ timeoutは、Angular=ダイジェストサイクル間の衝突と$ timeoutの出力は、新しい$ digestサイクルで実行されます。

私はそれらを説明しようとしました: apply、timeout、digest、evalAsyncの比較

役立つかもしれません。

13
Rahul Garg

私が理解する限り、$timeout$scope.$applyを暗黙的に呼び出すsetTimeoutのラッパーです。つまり、angularライフサイクルの外側で実行されますが、キックスタートangularライフサイクル自体。私が考えることができる唯一の「落とし穴」は、結果が利用可能になると期待している場合this$digest、「安全に適用」する別の方法を見つける必要があります(これは、$scope.$$phaseを介してのみ利用可能です)。

4
Jeff Hubbard