wir die Seiteninteraktionsleistung optimieren die Perspektive der Seitenflussanalyse. [Verwandte Tutorial-Empfehlung: „Angular Tutorial“]
Was ist Seitenflüssigkeit?
Die Seitenflüssigkeit wird durch die Bildrate FPS (Frames Per Second – übertragene Bilder pro Sekunde) bestimmt. Im Allgemeinen beträgt die Bildschirmaktualisierungsrate 60 Hz (Aktualisierung 60 Mal pro Sekunde), und die optimale Bildrate liegt bei 60 FPS Je flüssiger die Bildrate ist, desto flüssiger ist die Seite. 60 Hz bedeutet, dass der Bildschirm alle 16,6 ms aktualisiert wird, was bedeutet, dass das Rendern jeder Seite innerhalb von 16,6 ms abgeschlossen sein muss, andernfalls verliert die Seite Frames und friert ein.根因在于:浏览器中的JavaScript 执行和页面渲染会相互阻塞
.
In den Devtools von Chrome können wir Cmd+Shift+P ausführen und show fps eingeben, um das FPS-Panel schnell zu öffnen, wie in der folgenden Abbildung dargestellt:
Durch die Beobachtung des FPS-Panels können wir die Fließfähigkeit der aktuellen Seite leicht überwachen.
1 Faktoren, die die Seitenleistung beeinflussen
Ob die Seiteninteraktion reibungslos verläuft, hängt davon ab, ob die Seitenreaktion reibungslos ist, und die Seitenreaktion ist im Wesentlichen der Prozess des erneuten Renderns von Änderungen im Seitenstatus auf der Seite.
Der Seitenantwortprozess ist ungefähr wie folgt:
Im Allgemeinen nimmt die Ereignisverarbeitungslogik des Event-Handlers nicht zu viel Zeit in Anspruch, sodass die Faktoren, die sich auf die Angular-Leistung auswirken, hauptsächlich in异步事件触发
und变更检测
liegen. Im Allgemeinen nimmt die Ereignisverarbeitungslogik des Event-Handlers nicht zu viel Zeit in Anspruch, sodass die Faktoren, die sich auf die Angular-Leistung auswirken, hauptsächlich in der asynchronen Ereignisauslösung und der Änderungserkennung liegen.
Für Angular ist der Prozess des Seitenrenderings der Prozess der Änderungserkennung. Es versteht sich, dass die Änderungserkennung von Angular innerhalb von 16,6 ms abgeschlossen sein muss, um Seitenrahmenverluste und Verzögerungen zu vermeiden.
Die Leistung der Seitenantwort kann aus den folgenden drei Aspekten optimiert werden.
(1) Für die Trigger-Ereignisphase kann das Auslösen asynchroner Ereignisse reduziert werden , um die Gesamtzahl der Änderungserkennungen und erneuten Renderings zu reduzieren.
(2) Für die Event-Handler-Ausführungslogikphase kann die Ausführungszeit durch Optimierung der Komplexität reduziert werden Codelogik;
(3) Für die Datenbindungs- und DOM-Aktualisierungsphase der Änderungserkennung kann die Anzahl der Berechnungen der Änderungserkennung und der Vorlagendaten reduziert werden , um die
Renderzeit für (2) den Ereignishandler zu
verkürzenIm Detail wird nicht darauf eingegangen (1) (3) ) Optimierung
2 Optimierungsplan
2.1 Reduzieren Sie die Auslösung asynchroner Ereignisse
Angular Im Standard-Änderungserkennungsmodus lösen asynchrone Ereignisse die globale Änderungserkennung aus wird die Leistung von Angular erheblich verbessern.
Zu den asynchronen Ereignissen gehören Makro-Task-Ereignisse und Mikro-Task-Ereignisse
Die Optimierung asynchroner Ereignisse betrifft hauptsächlich Dokument-Listening-Ereignisse. Achten Sie beispielsweise auf Klick-, Mouseup-, Mousemove- und andere Ereignisse im Dokument.
Szenario für Abhörereignisse:
Renderer2.listen(document,…)
fromEvent(document,…)
document.addEventListener(…)
Das DOM-Abhörereignis muss entfernt werden, wenn es nicht ausgelöst werden muss.
Beispiel:Verwendungsszenarien für
den Eingabeaufforderungsfeldbefehl [pop]
: Filtern von Tabellenspalten, Klicken auf eine andere Stelle als das Symbol oder Scrollen der Seite, Ausblenden des Popup-Felds für den Spaltenfilter.Die vorherige Methode bestand darin, das Klickereignis und das Bildlaufereignis direkt zu überwachen des Dokuments im Pop-Befehl auf diese Weise: Der einzige Nachteil besteht darin, dass das Eingabeaufforderungsfeld nicht angezeigt wird, es aber dennoch Überwachungsereignisse gibt, was sehr unzumutbar ist.
Vernünftige Lösung: Hören Sie nur auf Klick- und Scroll-Ereignisse, wenn das Eingabeaufforderungsfeld angezeigt wird, und entfernen Sie die Abhörereignisse, wenn es ausgeblendet ist.
Für häufig ausgelöste DOM-Listening-Ereignisse können Sie RJX-Operatoren verwenden, um Ereignisse zu optimieren. Weitere Informationen finden Sie unter Rjx-Operatoren. RxJS-Murmeln.
2.2 Änderungserkennung
Was ist Änderungserkennung?
Um die Änderungserkennung zu verstehen, können wir nach Antworten auf die Ziele der Änderungserkennung suchen. Das Ziel der Winkeländerungserkennung besteht darin, das Modell (TypeScript-Code) und die Vorlage (HTML) synchron zu halten. Daher kann die Änderungserkennung als Folgendes verstanden werden: Erkennen von Modelländerungen und gleichzeitiges Aktualisieren der Vorlage ( DOM ) .
Was ist der Änderungserkennungsprozess?
Durch die Durchführung der Änderungserkennung in der Reihenfolge von oben nach unten im Komponentenbaum wird die Änderungserkennung zuerst an der übergeordneten Komponente und dann an den untergeordneten Komponenten durchgeführt. Überprüfen Sie zunächst die Datenänderungen der übergeordneten Komponente und aktualisieren Sie dann die Vorlage der übergeordneten Komponente. Wenn die Vorlage aktualisiert wird und auf die untergeordnete Komponente stößt, wird der an die untergeordnete Komponente gebundene Wert aktualisiert und dann die untergeordnete Komponente eingegeben, um festzustellen, ob die Vorlage vorhanden ist Wenn sich der Index des @Input-Eingabewerts geändert hat, markieren Sie die Unterkomponente als fehlerhaft, was eine anschließende Änderungserkennung erfordert. Aktualisieren Sie nach dem Markieren der Unterkomponente weiterhin die Vorlage hinter der Unterkomponente in der übergeordneten Komponente wurden aktualisiert, nehmen Sie Änderungen an der Unterkomponentenerkennung vor.
2.2.1 Prinzip der Winkeländerungserkennung
Im Standardmodus für die Änderungserkennung besteht das Prinzip, dass asynchrone Ereignisse die Änderungserkennung von Angular auslösen, darin, dass Angular die tick()-Methode von ApplicationRef aufruft, wenn asynchrone Ereignisse mithilfe von Zone.js verarbeitet werden, um sie von der Stammkomponente aus auszuführen zur Unterkomponente. Während des Initialisierungsprozesses der Angular-Anwendung wird eine Zone (NgZone) instanziiert und dann wird die gesamte Logik im _inner-Objekt des Objekts ausgeführt.
Zone.js implementiert die folgenden Klassen:
Das Prinzip des Erkennungsprozesses ist ungefähr wie folgt:
Benutzeroperationen lösen asynchrone Ereignisse aus (z. B. DOM-Ereignisse, Schnittstellenanforderungen ...)
=> Die ZoneTask-Klasse verarbeitet Ereignisse. Die runTask()-Methode von Zone wird in der Funktion invokeTask() aufgerufen. In der runTask-Methode übergibt Zone das Instanzattribut _zoneDelegate und ruft den Hook von ZoneSpec auf
=> die drei Hooks von ZoneSpec (onInvokeTask, onInvoke, onHasTask) übergeben checkStable () Funktion löst Zone.onMicrotaskEmpty.emit(null)-Benachrichtigung aus
=> Die Root-Komponente ruft tick() auf, nachdem sie onMicrotaskEmpty abgehört hat, und ruft detectChanges()
in der Tick-Methode auf, um die Erkennung von der Root-Komponente aus zu starten
=> ··· refreshView()
executeTemplate()
auf. Rufen Sie in executeTemplate
Methode templateFn()
auf, um den an die Vorlage und die Unterkomponente gebundenen Wert zu aktualisieren (这时候会去检测子组件的
输入引用是否改变,如果有改变,会将子组件标记为
,也就是该子组件需要变更检测
)
Detailliertes Flussdiagramm zum Änderungserkennungsprinzip:
Vereinfachen Sie den Prozess:
Lösen Sie ein asynchrones Ereignis aus
=> ZoneTask verarbeitet das Ereignis
=> ZoneDelegate ruft den ZoneSpec-Hook auf, um die onMicrotaskEmpty-Benachrichtigung auszulösen
=> die Root-Komponente empfängt die onMicrotaskEmpty-Benachrichtigung, führt tick() aus und beginnt mit der Erkennung und Aktualisierung des Doms
Wie aus dem obigen Code ersichtlich ist,当微任务为空的时候才会触发变更检测
.
Einfaches Flussdiagramm zum Prinzip der Änderungserkennung:
Angular-Quellcode-Analyse Zone.js Referenzblog.
2.2.2 Lösung zur Optimierung der Änderungserkennung
1) Verwenden Sie das OnPush-Modus-
Prinzip: Reduzieren Sie den Zeitaufwand für eine Änderungserkennung.
Der Unterschied zwischen dem OnPush-Modus und dem Standardmodus besteht darin, dass DOM-Abhörereignisse, Timer-Ereignisse und Versprechen keine Änderungserkennung auslösen. Der Komponentenstatus im Standardmodus ist immer CheckAlways, was bedeutet, dass die Komponente in jedem Erkennungszyklus getestet werden muss.
Im OnPush-Modus: Die folgenden Situationen lösen die Änderungserkennung
S1 und die @Input-Referenz der zu ändernden Komponente aus.
S2. Ereignisse, die an das DOM der Komponente gebunden sind, einschließlich Ereignisse, die an das DOM ihrer Unterkomponenten gebunden sind, wie z. B. Klicken, Senden und Klicken mit der Maus. @HostListener()
Hinweis:
DOM-Ereignisse, die über renderer2.listen() überwacht werden, lösen keine Änderungserkennung aus.
S3-
und Observable-Abonnementereignisse sind ebenfalls festgelegt gleichzeitig.
S4. Verwenden Sie die folgenden Methoden, um die Änderungserkennung manuell auszulösen:
ChangeDetectorRef.detectChanges(): Änderungserkennung für die aktuelle Komponente und Nicht-OnPush-Unterkomponenten auslösen.
ChangeDetectorRef.markForCheck(): Markiert die aktuelle Ansicht und alle ihre Vorgänger als fehlerhaft, und die Erkennung wird im nächsten Erkennungszyklus ausgelöst.
ApplicationRef.tick(): Löst keine Änderungserkennung aus
. 2)
Prinzip der Verwendung von NgZone.runOutsideAngular(): Reduzieren Sie die Anzahl der Änderungserkennungen
und schreiben Sie die globale Dom-Ereignisüberwachung in den Rückruf der NgZone.runOutsideAngular()-Methode Winkeländerungserkennung nicht auslösen. Wenn die aktuelle Komponente nicht aktualisiert wurde, können Sie den Hook „DetectChanges()“ von ChangeDetectorRef in der Rückruffunktion ausführen, um die Änderungserkennung der aktuellen Komponente manuell auszulösen.
Beispiel: dynamische Symbolkomponente app-icon-react
2.2.3 Debugging-Methode
1: Sie können das Angular DevTools-Plug-In in der Browserkonsole verwenden, um ein bestimmtes DOM-Ereignis und den Erkennungsstatus von Angular anzuzeigen:
Methode 2: Sie können Folgendes direkt in die Konsole eingeben: ng.profiler.timeChangeDetection(), um die Erkennungszeit anzuzeigen. Diese Methode kann die globale Erkennungszeit anzeigen. Referenzblog Profiling Angle Change Detection
2.3 Vorlagenoptimierung (HTML)
2.3.1 DOM-Rendering reduzieren: ngFor plus trackBy
Mit dem trackBy-Attribut von *ngFor ändert Angular nur die geänderten Einträge und rendert sie neu, ohne dass die gesamte Eintragsliste neu geladen werden muss.
Beispiel: Tabellensortierungsszenario. Wenn trackBy zu ngFor hinzugefügt wird, werden beim Rendern der Tabelle nur die Zeilen-Dom-Elemente verschoben. Wenn trackBy nicht hinzugefügt wird, werden zuerst die vorhandenen Tabellen-Dom-Elemente gelöscht und dann die Zeilen-Dom-Elemente hinzugefügt. Offensichtlich ist die Leistung beim Verschieben nur von Dom-Elementen viel besser.
2.3.2 Verwenden Sie keine Funktionen in Vorlagenausdrücken.
Sie können stattdessen eine Pipe oder eine Variable nach manueller Berechnung verwenden. Wenn Funktionen in Vorlagen verwendet werden, wird die Funktion unabhängig davon, ob sich der Wert geändert hat oder nicht, jedes Mal ausgeführt, wenn eine Änderungserkennung durchgeführt wird, was sich auf die Leistung auswirkt.
Szenarien für die Verwendung von Funktionen in Vorlagen:
2.3.3 Reduzieren Sie die Verwendung von ngFor.
Die Verwendung von ngFor beeinträchtigt die Leistung, wenn die Datenmenge groß ist.
Beispiel:
Verwendung von ngFor:
ngFor nicht verwenden: Leistung um etwa das Zehnfache verbessert