OnPushとChangeDetectorRefでAngularのパフォーマンスを向上したい
Created:
Modified:
AngularのOnPush戦略
Angularのパフォーマンスを向上するために
changeDetection: ChangeDetectionStrategy.OnPush,
を導入した。
これにより入力プロパティが変更された場合、またはコンポーネント自身やその子コンポーネントがイベントを発火した場合にのみ、変更検知するようになる。
そもそもAngularのデフォルト変更検知は
- ブラウザイベント
- タイマーイベント
- HTTPリクエストの完了
- Promiseの解決/拒否
でブラウザイベントが発生するとすべてのコンポーネントが変更検知の対象になるらしい。
つまり非常にコストが高い。
そのためOnPush
戦略が重要になる。
ちなみにベストプラクティスは
デフォルトではOnPushを適用せず、パフォーマンスが問題になったり、上記で挙げた「OnPushを検討すべきコンポーネント」の特性に合致したりする場合に限定して導入を検討する
とのことだった。
で、導入した場合、データが非同期で更新された場合や、参照が変更されないオブジェクトのプロパティが更新された場合など、Angularが自動的に変更を検知できないケースが発生する。
そこで明示的に変更を検知するためにChangeDetectorRef
を使用する。
ChangeDetectorRefはコンポーネントの変更検知器への参照を提供する
開発者が変更検知のタイミングを細かく制御できるようにするChangeDetectorRef
は4つのメソッドを持つ。
markForCheck
次回の変更検知サイクルでチェックする必要があることをマークするメソッド。
markForCheck()
を呼び出すだけではすぐに変更検知は実行されず、次の変更検知サイクル時に検知の対象となる。
「次のチェックで、忘れずにこのコンポーネントも見てね!」いつ使う? コンポーネントの中のデータが非同期(例:setTimeoutやHTTPリクエストの結果など)で変わったけど、そのデータの「箱」(参照)自体は変わっていないとき。Angularは箱の中身が変わっただけでは、デフォルトで気付いてくれません。
detectChanges
直ちに変更検知サイクルを強制的に実行する。頻繁な呼び出しはパフォーマンスに影響を与える可能性がある。
「今すぐ!このコンポーネントをチェックして見た目を更新して!」いつ使う? コンポーネントの中のデータが非同期(例:setTimeoutやHTTPリクエストの結果など)で変わったけど、そのデータの「箱」(参照)自体は変わっていないとき。Angularは箱の中身が変わっただけでは、デフォルトで気付いてくれません。
detach()
現在のコンポーネントを変更検知ツリーから切り離す。そのコンポーネントとその子孫コンポーネントは、明示的にreattach()
されるまで、以降の変更検知サイクルではチェックされなくなる。コンポーネントがめったに変更されない場合とかに使える。
「このコンポーネント、しばらくお休みさせて!」いつ使う? Angularが通常検知しないような場所(例:ngZone.runOutsideAngular()の中)でデータが更新されたり、特定のタイミングでどうしても画面をすぐに更新したいとき。
reattach()
detach()
で切り離されたコンポーネントを変更検知ツリーに再アタッチする。再び通常の変更検知サイクルに含まれるようになる。
「お休み終わり!またチェックしてね!」いつ使う? ほとんどデータが変わることがない、または特定の条件が満たされない限り、画面を更新する必要がないコンポーネントがある場合。大量のコンポーネントがある中で、一部を休ませて全体の負担を減らしたいときに役立ちます。
うーん、2年間くらい触ってて初めてしっかり理解を試みた。