今回は、Angular コードを最適化する方法と、Angular コードを最適化するための注意点について説明します。以下に実際の事例を示します。
概要
Angular 4 におけるダーティ値の検出は古いトピックであり、このモデルを理解することが Angular のパフォーマンス最適化の基礎となります。したがって、今日は Angular 4 のダーティ値検出の原理について説明し、パフォーマンスを最適化するためのヒントをいくつか見ていきます。
エントリー ポイント - Zone.js
Angular 4 は MVVM フレームワークです。データ モデル (Model) がビュー モデル (ViewModel) に変換された後、ビュー (View) にバインドされ、肉眼で見えるページにレンダリングされます。したがって、データ モデルが変更される時点を発見することが、ページを更新してダーティ値検出を呼び出すための鍵となります。
分析の結果、エンジニアはデータの変更がマクロタスクやマイクロタスクなどの非同期イベントによって引き起こされることが多いことを発見しました。したがって、ブラウザ内のすべての非同期 API を書き換えることで、データの変更をソースから効果的に監視できます。 Zone.js はそんなモンキースクリプト(Monkey Patch)です。 Angular 4 は、カスタマイズされたゾーン (NgZone) を使用します。これは、データが変更される可能性があり、ビュー内のデータを更新する必要があることを Angular に通知します (ダーティ値の検出)。
ダーティ値検出(変更検出)
ダーティ値検出の基本原理は、古い値を保存し、検出する際に現時点の新しい値と古い値を比較することです。それらが等しい場合、変更はありません。そうでない場合は、変更が検出され、ビューを更新する必要があります。
Angular 4 はページを複数のコンポーネントに分割してコンポーネント ツリーを形成します。ダーティ値検出に入ると、ルートコンポーネントから上から下へ検出が行われます。 Angular には、Default と OnPush という 2 つの戦略があります。これらはコンポーネント上で構成され、ダーティ値検出時のさまざまな動作を決定します。
Default - デフォルト戦略
ChangeDetectionStrategy.Default。また、データを変更する可能性のあるイベントが発生すると、このコンポーネントが常にテストされることも意味します。
ダーティ値検出の動作は、基本的に次のステップとして理解できます。 1) サブコンポーネントにバインドされているプロパティを更新します。2) サブコンポーネントの NgDoCheck および NgOnChanges ライフサイクル フックを呼び出します。3) 独自の DOM を更新します。4) サブコンポーネントのダーティ値を検出します。これはルートコンポーネントから始まる再帰方程式です。
// This is not Angular code function changeDetection(component) { updateProperties(component.children); component.children.forEach(child => { child.NgDoCheck(); child.NgOnChanges(); }; updateDom(component); component.children.forEach(child => changeDetection(child)); }
私たち開発者は、DOM の更新順序と NgDoCheck と NgOnChanges の呼び出し順序に細心の注意を払います。
DOM 更新は深さ優先である
NgDoCheck と NgOnChanges は深さ優先ではない (深さ優先でもない)
OnPush - 単一の検出戦略
ChangeDetectionStrategy.OnPush。このコンポーネントは、入力プロパティが変更されたとき (OnPush) にのみ検出されます。したがって、入力が変化しない場合は、初期化中にのみ検出され、単一検出とも呼ばれます。その他の動作はデフォルトと一致します。
OnPush は入力への参照のみを検出することに注意してください。入力オブジェクトのプロパティを変更しても、現在のコンポーネントのダーティ値検出はトリガーされません。
OnPush 戦略はパフォーマンスを向上させますが、バグのホットスポットでもあります。多くの場合、解決策は入力を不変形式に変換し、入力の参照を強制的に変更することです。
ヒント
データバインディング
Angularには3つの合法的なデータバインディングメソッドがありますが、それらのパフォーマンスは異なります。
データを直接バインドする
<ul> <li *ngFor="let item of arr"> <span>Name {{item.name}}</span> <span>Classes {{item.classes}}</span><!-- Binding a data directly. --> </li> </ul>
ほとんどの場合、これが最適な実行方法です。
関数呼び出し結果をバインド
<ul> <li *ngFor="let item of arr"> <span>Name {{item.name}}</span> <span>Classes {{classes(item)}}</span><!-- Binding an attribute to a method. The classes would be called in every change detection cycle --> </li> </ul>
各ダーティ値検出プロセスで、クラス方程式を 1 回呼び出す必要があります。ユーザーがページをスクロールし、複数のマクロタスクが生成され、各マクロタスクが少なくとも 1 つのダーティ値チェックを実行すると想像してください。特別な必要がない場合は、この使用方法はできるだけ避けてください。
Bind data+pipe
<ul> <li *ngFor="let item of instructorList"> <span>Name {{item.name}}</span> <span>Classes {{item | classPipe}}</span><!-- Binding data with a pipe --> </li> </ul>
ダーティ値検出classPipeが呼び出されるたびに行うバインディング関数と同様です。ただし、Angular はパイプを最適化し、キャッシュを追加しました。項目が前回と等しい場合は、結果が直接返されます。
NgFor
ほとんどの場合、NgFor は trackBy 方程式とともに使用する必要があります。それ以外の場合、NgFor は各ダーティ値検出プロセス中にリスト内の各項目の DOM を更新します。
@Component({ selector: 'my-app', template: ` <ul> <li *ngFor="let item of collection;trackBy: trackByFn">{{item.id}}</li> </ul> <button (click)="getItems()">Refresh items</button> `, }) export class App { collection; constructor() { this.collection = [{id: 1}, {id: 2}, {id: 3}]; } getItems() { this.collection = this.getItemsFromServer(); } getItemsFromServer() { return [{id: 1}, {id: 2}, {id: 3}, {id: 4}]; } trackByFn(index, item) { return index; } }
この記事の事例を読んだ後は、この方法を習得したと思います。さらに興味深い情報については、php 中国語 Web サイトの他の関連記事に注目してください。
推奨読書:
以上がAngular コードを最適化する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。