AngularJSの$ evalAsyncと$ timeoutの違いは何ですか?


180

私は今しばらくAngularJSを使用していて、たまに$ timeoutを使用する必要があることを発見しました(通常、jQueryプラグインを初期化するようです)。

最近、私はダイジェストサイクルをよりよく、より深く理解しようと努めており、$ evalAsync関数に出くわしました。

その関数はと同様の結果を生成するよう$timeoutですが、遅延を与えないだけです。使用$timeoutするたびに遅延が0になったので、$evalAsync代わりに使用するべきだったのかと思います。

2つの間に基本的な違いはありますか?どちらを使用するのですか?どっちを使うのがいいのか気になります。

回答:


263

私は最近、基本的にこの質問にここで答えました:https : //stackoverflow.com/a/17239084/215945 (この回答は、Miskoとのいくつかのgithub交換にリンクしています)。

要約する:

  • コードを使用して、キューに入れられている場合ディレクティブから$ evalAsyncを、それが実行する必要があります後に DOMが角度によって操作されていますが、前にブラウザのレンダリング
  • コードを使用してキューに入っている場合、コントローラから$ evalAsyncを、それが実行する必要があります前に、 DOMは、角度によって操作されている(とブラウザのレンダリングの前に) -めったにあなたはこれをしたいんです
  • コードが$ timeoutを使用してキューに入れられている場合、コードは、DOMがAngularによって操作された、およびブラウザーがレンダリングされたに実行される必要があります(これにより、ちらつきが発生する場合があります)。

15
ご説明ありがとうございます。でも、よくわからないことが一つあります。コントローラーまたはディレクティブから$ evalAsyncを呼び出す場合、なぜ違いがあるのですか?asyncQueueは、それがコントローラーから登録されたかディレクティブから登録されたかを認識せず、現在のスコープでキューに入れるだけです。コントローラーとコントローラーのどちらで実行するかと関係がありますか?その部分を理解したいだけです。
dnc253 2013年

@ dnc253、私はAngularコードを見ていないので、(良い)質問に対する答えがわかりません。うまくいけば、他の誰かがコメントできます。
Mark Rajcok 2013年

15
「ディレクティブから」は「ディレクティブのリンク機能から」を意味しますか?または、ディレクティブのリンクまたはコントローラーメソッドから実行された場合の動作は本当ですか?
SimplGy 2014

5
ええ

1
@MarkRajcok、ここで明確にしてください:コードがディレクティブから$ evalAsyncを使用してキューに入れられる場合、DOMがAngularによって操作された後に実行する必要があります-DOMがこのディレクティブまたは他のディレクティブによって操作された後に実行する必要がありますか?
Max Koretskyi

59

複雑なアプリケーションを構築する場合は、選択にパフォーマンスの影響があることに注意してください。また、マークの回答をより技術的な詳細で完了したいと思います。

  • $ timeout(callback)は、現在のダイジェストサイクルが完了するまで待機し(つまり、すべてのモデルとDOMの角度更新)、コールバックを実行します-潜在的に角度モデルに影響します-次に$applyルート$ scopeでフルを起動し、再ダイジェストしますすべて。

  • 一方、$ evalAsync(callback)は、現在または次のダイジェストサイクルにコールバックを追加します。つまり、ダイジェストサイクル内(たとえば、いくつかのng-clickディレクティブから呼び出された関数内)にいる場合、これは何も待機せず、コードはすぐに実行されます。たとえばのような非同期呼び出し内にいる場合setTimeout、新しいダイジェストサイクル($apply)がトリガーされます。

したがって、パフォーマンス$evalAsyncの観点からは、コードを実行する前にビューが最新であることが重要である場合を除いて、たとえば要素の幅などのDOm属性にアクセスする必要がある場合を除いて、常にを呼び出すことをお勧めします。

$ timeout、$ evalAsync、$ digest、$ applyの違いの詳細が必要な場合は、他の質問に対する私の回答を読んでくださいhttps : //stackoverflow.com/a/23102223/1501926

また、ドキュメントも必ずお読みください。

$ evalAsyncは、式がいつ実行されるかを保証しません。

  • 評価をスケジュールした関数の後で(できればDOMレンダリングの前に)実行されます。
  • 式の実行後、少なくとも1つの$ digestサイクルが実行されます。

注:この関数が$ digestサイクルの外で呼び出されると、新しい$ digestサイクルがスケジュールされます。ただし、$ apply呼び出し内からモデルを変更するコードを常に呼び出すことをお勧めします。これには、$ evalAsyncを介して評価されるコードが含まれます。


DOM属性にアクセスする必要がある場合に$ timeoutが必要な理由を説明してください。<table width = "{{x}}">がng-bindの監視機能でメモリ内のdom属性を更新しない場合、ダイジェストサイクルが終了するまでビューを再描画する機会がないことを理解しています。
Sridhar Chidurala

2
@SridharChiduralaは、ダイジェストサイクル中にDOM( "HTML")が更新されるため、mofificationを読み取る前に、DOMが完了するのを待つ必要があります。ただし、これはAngularで推奨されxていません。DOMからではなく、スコープから直接読み取る必要があるため、何も待つ必要はありません。また、ng-style廃止されたwidthプロパティではなく、CSSを使用することをお勧めします。さらにヘルプが必要な場合は、StackOverflowで新しい質問を開いてください。
フロリボン2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.