AngularjsとAngularのダーティチェックメカニズムの理解
Angularjs Angulars Understanding Dirty Checking Mechanism
「ダーティチェック」はAngularのコアメカニズムの1つです。これは、双方向のデータバインディングとMVVMパターンを実装するための重要な基盤です。
AngularJSで一般的に使用される関数:$ apply、$ watch、$ digest
$ digestは内部関数であるため、通常のアプリケーションコードで直接呼び出すことはできません。アクティブにトリガーするには、scope。$ apply関数を呼び出す必要があります。これは、Angularの「ダーティチェックメカニズム」をトリガーする一般的なパブリックインターフェイスです。 $ digestループには、実際には2つのwhileループが含まれています。それらは、$ evalAsyncを処理するための非同期操作キューと、$ watchを処理するためのウォッチャーキューです。ループがトリガーされると、現在の$ scopeとそのすべての子$ scopeに登録されているすべてのウォッチャー関数をトラバースします。すべてのウォッチャー機能を繰り返すことは、ダーティチェックのラウンドになります。ダーティチェックのラウンドを実行した後、いずれかのウォッチャーによって監視されている値が変更された場合、すべてのウォッチャー機能が監視している値が変更されていないことを報告するまで、ダーティチェックの別のラウンドが再度実行されます。ループが終了すると、モデルの変更がDOMで更新されます。これは、DOM属性が頻繁に更新されるのを防ぐために行われます。
ダーティチェックの一般的な理解:式{{aaa.x}}、AngularJSはデータをレンダリングするだけでなく、特定の値のオブザーバーも作成します。その後、プログラムに何かが起こったときはいつでも、AngularJSは観測中の値が変更されたかどうかをチェックします。その場合は、式を再レンダリングします。これらのオブザーバーを実行するプロセスは、ダーティチェックと呼ばれます。
AngularはZone.jsを参照してダーティチェックを処理します
NgZoneは、Observablesに基づく追加のAPIを備えたフォークゾーンです。
ページにデータの変更を適用するには、最初にデータの変更を検出する必要があります。データの変更は通常、次のような非同期イベントで発生します。
ブラウザイベント、例:クリック、送信
setTimeoutおよびsetInterval
XHR、リモートサーバーからデータを取得します...
誰がAngularに通知しましたか?
class ApplicationRef { changeDetectorRefs:ChangeDetectorRef[] = [] // applicationRef listens to onTurnDone events in the constructor constructor(private zone: NgZone) { this.zone.onTurnDone .subscribe(() => this.zone.run(() => this.tick())) } // The tick function traverses all detector interfaces/objects to perform detection tick() { this.changeDetectorRefs .forEach((ref) => ref.detectChanges()) } } }
変更検出はどのように機能しますか?
各コンポーネントには独自の変更検出器があります
変更検出ツリー:有向グラフ一方向のデータフローは常に上から下への変更検出を実行します
デフォルトでは、Angularは保守的であり、すべてのコンポーネントが毎回チェックされます
変更検出戦略
列挙型ChangeDetectionStrategy {
OnPush:0 //入力が変更された場合にのみビューを変更します。入力属性が変更されていない場合、Angularは変更検出ツリー全体をスキップできます
デフォルト:1 //デフォルトのポリシー。変更の検出は、明示的に無効になるまで自動的に行われます。
}
NgDoCheckフックと変更の検出
サブコンポーネントのプロパティを更新します
サブコンポーネントにあるNgDoCheckライフサイクルフックを呼び出す
現在のコンポーネントのDOMを更新します
サブコンポーネントの変更検出を実行します
NgDoCheckの役割:markForCheckおよびOnPushと連携します
export class AppComponent { @Input() data public id constructor(private cdr: ChangeDetectorRef){} ngOnChanges() { // When data changes, update id this.id = this.data.id } ngDoCheck() { // Check whether the attribute of the data object has changed in ngDoCheck if( this.id !== this.data.id ) { this.cdr.markForCheck() } } }
@Component({ template:'{{num}}' changeDetection: ChangeDetectionStrategy.OnPush }) export class NumComponent implements OnInit { @Input() addItem: Observable num = 0 constructor(private cdr: ChangeDetectorRef){} ngOnInit() { this.addItem.subscribe(()=>{ this.num++ this.cdr.markForCheck()//Manually notify Angular to detect }) } }
質問?
OnPush戦略では、コンポーネントに属性の更新がない場合でも、ngOnCheckフックが呼び出されるのはなぜですか?
子コンポーネントがOnPushストラテジーを使用し、親コンポーネントが使用しない可能性があります。子コンポーネントの@Inputプロパティは変更されていませんが、ngOnCheckフックは現在のコンポーネント変更の呼び出しを実行します。