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フックは現在のコンポーネント変更の呼び出しを実行します。