angularパフォーマンスを最適化するにはどうすればよいですか?次の記事では、Angular のパフォーマンス最適化ソリューションである変更検出について詳しく説明します。
ページの流暢さとは何ですか?
ページの流暢さはフレーム レート FPS (1 秒あたりのフレーム数 - 1 秒あたりに送信されるフレーム数) によって決まります。一般に、主流のブラウザの画面リフレッシュ レートは 60 Hz (1 秒あたり 60 回リフレッシュされます)最適なフレーム レートは 60 FPS です。フレーム レートが高いほど、ページは滑らかになります。60 Hz は、表示画面が 16.6 ミリ秒ごとに更新されることを意味します。つまり、各ページのレンダリングは 16.6 ミリ秒以内に完了する必要があり、そうでない場合はページが更新されません。フレーム落ちやカクつきが発生します。
根本的な原因は次のとおりです。ブラウザでの JavaScript の実行とページのレンダリングが相互にブロックします。
1 ページのパフォーマンスに影響を与える要因
ページのインタラクションがスムーズかどうかは、ページの応答がスムーズかどうかによって決まります。ページ応答
は基本的に、ページ ステータスの変化をページに再レンダリングするプロセスです。 ページ応答プロセスは大まかに次のとおりです。一般に、イベント ハンドラーのイベント処理ロジックはそれほど多くの時間を消費しないため、影響を与える主な要因は次のとおりです。角度のパフォーマンスは、
非同期イベントトリガー と
変更検出
(1) トリガー イベント ステージでは、非同期イベントのトリガーを減らす
により、全体的な変更検出と再レンダリングの数を減らすことができます。 (2) イベント ハンドラー実行ロジック ステージの場合、複雑なコード ロジックを最適化することで実行時間を短縮できます;(3) 変更検出検出のデータ バインディングと DOM ステージの更新の場合、 変更検出 と テンプレート データ
の計算数を減らしてレンダリング時間を短縮できます; (2) イベント ハンドラーについては、特定の問題を分析する必要があります。詳細は議論せずに、主に ( 1) (3) 最適化2 最適化計画
2.1非同期イベントのトリガーを減らす
Angular のデフォルトの変更検出モードでは、非同期イベントはグローバル変更検出をトリガーするため、非同期イベントのトリガーを減らすと、Angular のパフォーマンスが大幅に向上します。 非同期イベントには、マクロ タスク (マクロ ミッション) イベントとマイクロ タスク マイクロタスク イベントが含まれます。 これは主に、Document の監視イベントを対象としています。たとえば、ドキュメント上のクリック、マウスアップ、マウス移動などのイベントをリッスンします。 リスニング イベント シナリオ: Renderer2.listen(document,…) fromEvent(document,…) document.addEventListener(…) DOM リスニング イベントは、不要になったら削除する必要があります。 ###例: [pop] プロンプト ボックス コマンド
使用シナリオ: テーブル列のフィルタリング、アイコン以外の場所をクリック、またはページ スクロール、列フィルタリングのポップアップ ボックスの非表示
前のこのアプローチは、pop コマンドでドキュメントのクリック イベントとスクロール イベントを直接監視する方法でした。プロンプト ボックスが表示されないという欠点がありますが、監視イベントは依然として存在しており、これは非常に不合理です。
合理的な解決策: プロンプト ボックスが表示されている場合のみクリック イベントとスクロール イベントをリッスンし、プロンプト ボックスが非表示になっている場合はリッスン イベントを削除します。
頻繁にトリガーされる DOM リスニング イベントの場合、rjx 演算子を使用してイベントを最適化できます。詳細については、Rjx 演算子を参照してください。 RxJS ビー玉。
2.2 変更検出
変更検出とは何ですか?
変更検出を理解するには、変更検出の目標から答えを見つけることができます。角度変化検出の目的は、モデル (TypeScript コード) とテンプレート (HTML) の同期を維持することです。したがって、変更の検出は次のように理解できます。 モデルの変更を検出しながら、テンプレートを更新します ( DOM ) 。
変更検出プロセスとは何ですか?
## コンポーネント ツリーで変更検出をtop-down の順序で実行します。つまり、最初に親コンポーネントで変更検出を実行し、次に親コンポーネントで変更検出を実行します。子コンポーネント コンポーネントは変更検出を実行します。まず親コンポーネントのデータ変更を確認し、次に親コンポーネント テンプレートを更新します。テンプレートを更新するとき、子コンポーネントに遭遇すると、子コンポーネントにバインドされている値が更新され、子コンポーネントに入り、 @Input 入力値のインデックスが変更されました。変更された場合は、サブコンポーネントをダーティとしてマークします。これには、後続の変更検出が必要です。サブコンポーネントをマークした後、親コンポーネントのサブコンポーネントの背後にあるテンプレートの更新を続けます。すべての親コンポーネント テンプレートが終了した後、更新されている場合は、サブコンポーネントを変更します。
2.2.1 Angular の変更検出の原則 デフォルトの変更検出デフォルト モードでは、Angular の変更検出をトリガーする非同期イベントの原則は、Zone.js を使用して非同期イベントを処理するときに Angular が ApplicationRef を呼び出すことです。 check() メソッドは、ルート コンポーネントからその子コンポーネントへの変更検出を実行します。 Angular アプリケーションの初期化プロセス中に、ゾーン (NgZone) がインスタンス化され、すべてのロジックがオブジェクトの _inner オブジェクト内で実行されます。 Zone.js は次のクラスを実装します:ユーザー操作により非同期イベントがトリガーされます (例: DOM イベント、インターフェイス リクエストなど)
=> ZoneTask クラスはイベントを処理します。ゾーンの runTask() メソッドは invokeTask() 関数で呼び出されます。 runTask メソッドでは、ゾーンは _zoneDelegate インスタンス属性を通じて ZoneSpec のフックを呼び出します
=> ZoneSpec の 3 つのフック (onInvokeTask、onInvoke) 、onHasTask) フックでは、zone.onMicrotaskEmpty.emit(null) 通知が checkStable() 関数によってトリガーされます。
=> ルート コンポーネントは onMicrotaskEmpty をリッスンし、tick() を呼び出します。メソッドは
detectChanges()from を呼び出します。ルート コンポーネントは => · · ·
Call executeTemplate()
の検出を開始します。 executeTemplate
メソッドは templateFn () を呼び出します。
テンプレートとサブコンポーネントのバインディング値を更新します (この時点で、サブコンポーネントの
@Input( ) 入力参照が変更されました。変更がある場合、サブコンポーネントはマークされます。
Dirty、つまり、サブコンポーネントは変更検出が必要です
)変化検出原理の詳細なフローチャート:
プロセスを簡略化します:
非同期イベントをトリガーします
=> ZoneTask がイベントを処理します
=> ZoneDelegate がフックを呼び出しますZoneSpec のトリガー onMicrotaskEmpty notification
=> ルート コンポーネントは onMicrotaskEmpty 通知を受け取り、tick() を実行し、dom
As の検出と更新を開始します。上記のコードからわかるように、マイクロタスクが空の場合にのみ変更検出がトリガーされます
。
単純な変更検出原理のフローチャート:
Angular ソース コード分析 Zone.js リファレンスblog。
2.2.2 変更検出の最適化計画
1) OnPush モードを使用する
原則: 1 つの変更検出にかかる時間を削減します。
OnPush モードと Default モードの違いは、DOM リスニング イベント、タイマー イベント、Promise が変更検出をトリガーしないことです。デフォルト モードのコンポーネントのステータスは常に CheckAlways です。これは、コンポーネントが検出サイクルごとにテストされる必要があることを意味します。
OnPush モード: 次の状況では変更検出がトリガーされます
S1. コンポーネントの @Input 参照が変更されます。
S2. コンポーネントの DOM にバインドされたイベント (クリック、送信、マウス ダウンなど、そのサブコンポーネントの DOM にバインドされたイベントを含む)。 @HostListener()
注:
renderer2.listen() を介してリッスンされる dom イベントは、変更検出をトリガーしません。
dom.addEventListener() を介したネイティブ リスニング メソッドは、変更検出をトリガーしません。変更検出をトリガーしません。 変更検出をトリガーします。
S3、監視可能なサブスクリプション イベント、および非同期パイプを同時に設定します。
S4. 次のメソッドを使用して変更検出を手動でトリガーします:
ChangeDetectorRef.detectChanges(): 現在のコンポーネントおよび非 OnPush サブコンポーネントの変更検出をトリガーします。
ChangeDetectorRef.markForCheck(): 現在のビューとそのすべての祖先をダーティとしてマークすると、次の検出サイクルで検出がトリガーされます。
ApplicationRef.tick(): 変更検出はトリガーされません
2) NgZone.runOutsideAngular() を使用します
#原則: 変更検出の数を減らす グローバル DOM イベント監視は NgZone.runOutsideAngular() メソッドのコールバックに記述されます。DOM イベントは Angular の変更検出をトリガーしません。現在のコンポーネントが更新されていない場合は、コールバック関数で ChangeDetectorRef の detectChanges() フックを実行して、現在のコンポーネントの変更検出を手動でトリガーできます。 例: app-icon-react 動的アイコン コンポーネント 2.2.3 デバッグ方法 方法 1: で制御できます。台湾のブラウザでは、Angular DevTools プラグインを使用して、特定の DOM イベント、角度検出を表示します。## 方法 2: ng.profiler.timeChangeDetection() を直接入力できます。コンソールを使用して検出時間を表示すると、グローバルな検出時間を表示できます。参考ブログ
プロファイリング角度変化検出 2.3 テンプレート (HTML) の最適化2.3.1 DOM の削減レンダリング: ngFor と trackBy
*ngFor の trackBy 属性を使用すると、Angular はエントリのリスト全体を再ロードすることなく、変更されたエントリのみを変更して再レンダリングします。
例: テーブルの並べ替えシナリオ。 ngFor に trackBy を追加すると、テーブルのレンダリング時に行 dom 要素のみが移動しますが、trackBy を追加しない場合は、既存のテーブル dom 要素が削除されてから行 dom 要素が追加されます。明らかに、dom 要素のみを移動する場合のパフォーマンスは大幅に向上します。
2.3.2 テンプレート式では関数を使用しないでください
Angular テンプレート式では関数呼び出しを使用しないでください。代わりにパイプを使用することも、手動計算後に変数を使用することもできます。テンプレート内で関数を使用している場合、値が変更されたかどうかに関係なく、変更検出が行われるたびに関数が実行されるため、パフォーマンスに影響します。
テンプレートで関数を使用するシナリオ:
2.3.3 ngFor の使用を減らす
データ量が多い場合、ngFor を使用するとパフォーマンスに影響します。
例:
ngFor を使用する:
##ngFor を使用しない場合: パフォーマンスが約 10 倍向上 プログラミング関連の知識について詳しくは、プログラミング ビデオをご覧ください。 !
以上がAngular でパフォーマンスを最適化するにはどうすればよいですか?変化検出方法の簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。