In Chrome 102 finden Sie in den Entwicklertools einen neuen experimentellen Bereich namens Leistungsstatistiken. In diesem Beitrag geht es nicht nur darum, warum wir an einem neuen Bereich gearbeitet haben, sondern auch um die technischen Herausforderungen, vor denen wir standen, und die Entscheidungen, die wir im Laufe der Zeit getroffen haben.
Warum ein weiteres Steuerfeld erstellen?
(Falls Sie es noch nicht gesehen haben, haben wir ein Video dazu veröffentlicht, warum wir das Performance Insights-Panel entwickelt haben und wie Sie damit umsetzbare Informationen zur Leistung Ihrer Website erhalten können.)
Das vorhandene Leistungspanel ist eine gute Ressource, wenn Sie alle Daten für Ihre Website an einem Ort sehen möchten. Wir hatten jedoch den Eindruck, dass es etwas unübersichtlich sein kann. Wenn Sie kein Leistungsexperte sind, ist es schwierig, genau zu wissen, worauf Sie achten müssen und welche Teile der Aufzeichnung relevant sind.
Rufen Sie das Insights-Panel auf. Dort können Sie weiterhin eine Zeitachse Ihres Traces aufrufen und die Daten untersuchen. Außerdem erhalten Sie eine praktische Liste der wichtigsten „Insights“, die DevTools für untersuchenswert hält. Mit Insights werden Probleme wie renderblockierende Anfragen, Layoutverschiebungen und lange Tasks identifiziert, die sich alle negativ auf die Seitenladeleistung Ihrer Website und insbesondere auf die Core Web Vitals (CWV)-Werte Ihrer Website auswirken können. Neben der Kennzeichnung von Problemen erhalten Sie in Performance Insights auch umsetzbare Vorschläge zur Verbesserung Ihrer CWV-Werte sowie Links zu weiteren Ressourcen und Dokumentationen.
Dieses Feld ist experimentell und wir freuen uns über Ihr Feedback. Bitte teilen Sie uns mit, wenn Sie Fehler feststellen oder Funktionsanfragen haben, die Ihnen bei der Optimierung der Leistung Ihrer Website helfen könnten.
So haben wir Leistungsstatistiken entwickelt
Wie der Rest von DevTools haben wir Performance Insights in TypeScript entwickelt und Webkomponenten verwendet, die auf lit-html basieren, um die Benutzeroberfläche zu erstellen. Der Unterschied besteht darin, dass die primäre Benutzeroberfläche ein HTML-Element canvas
ist und die Zeitachse auf diesen Canvas gezeichnet wird. Ein Großteil der Komplexität ergibt sich aus der Verwaltung dieses Canvas: Es müssen nicht nur die richtigen Details an der richtigen Stelle gezeichnet werden, sondern auch Mausereignisse verwaltet werden (z. B. wo hat der Nutzer auf den Canvas geklickt?). Haben sie auf ein Ereignis geklickt, das wir gezeichnet haben? Und wird das Canvas effektiv neu gerendert?
Mehrere Tracks auf einem einzigen Canvas
Für eine bestimmte Website gibt es mehrere „Tracks“, die gerendert werden sollen. Jeder Track steht für eine andere Datenkategorie. Im Bereich „Statistiken“ werden standardmäßig drei Tracks angezeigt:
Da wir dem Infobereich immer wieder neue Funktionen hinzufügen, werden auch immer mehr Titel verfügbar sein.
Ursprünglich hatten wir die Idee, für jeden dieser Tracks einen eigenen <canvas>
zu rendern, sodass die Hauptansicht aus mehreren vertikal gestapelten Canvas-Elementen bestehen würde. Das würde das Rendern auf Track-Ebene vereinfachen, da jeder Track isoliert gerendert werden könnte und es keine Gefahr gäbe, dass ein Track außerhalb seiner Grenzen gerendert wird. Dieser Ansatz hat jedoch zwei große Probleme:
canvas
-Elemente sind aufwendig zu rendern. Mehrere Canvas-Elemente sind aufwendiger als ein Canvas-Element, auch wenn dieses größer ist.
Das Rendern von Overlays, die sich über mehrere Tracks erstrecken (z. B. vertikale Linien zur Markierung von Ereignissen wie der FCP-Zeit), wird komplex: Wir müssen auf mehreren Canvas rendern und dafür sorgen, dass sie alle zusammen gerendert werden und richtig ausgerichtet sind.
Da wir nur ein canvas
für die gesamte Benutzeroberfläche verwendet haben, mussten wir herausfinden, wie wir sicherstellen können, dass jeder Track an den richtigen Koordinaten gerendert wird und nicht in einen anderen Track überläuft. Wenn ein bestimmter Track beispielsweise 100 Pixel hoch ist, können wir nicht zulassen, dass etwas gerendert wird, das 120 Pixel hoch ist und in den Track darunter überläuft. Zur Behebung dieses Problems können wir clip
verwenden. Bevor wir jeden Track rendern, zeichnen wir ein Rechteck, das das sichtbare Track-Fenster darstellt. So wird sichergestellt, dass alle Pfade, die außerhalb dieser Grenzen gezeichnet werden, vom Canvas abgeschnitten werden.
canvasContext.beginPath();
canvasContext.rect(
trackVisibleWindow.x, trackVisibleWindow.y, trackVisibleWindow.width, trackVisibleWindow.height);
canvasContext.clip();
Außerdem sollte jeder Track seine vertikale Position nicht kennen müssen. Jeder Track sollte so gerendert werden, als ob er an der Position (0, 0) gerendert würde. Die Gesamtposition des Tracks wird von einer Komponente auf höherer Ebene (TrackManager
) verwaltet. Dazu können Sie translate
verwenden, um den Canvas um eine bestimmte (x, y)-Position zu verschieben. Beispiel:
canvasContext.translate(0, 10); // Translate by 10px in the y direction
canvasContext.rect(0, 0, 10, 10); // draw a rectangle at (0, 0) that’s 10px high and wide
Obwohl im rect
-Code 0, 0
als Position festgelegt ist, wird das Rechteck aufgrund der angewendeten Gesamtübersetzung an der Position 0, 10
gerendert. So können wir auf Track-Basis arbeiten, als würden wir bei (0, 0) rendern. Unser Track-Manager sorgt dann dafür, dass jeder Track beim Rendern so übersetzt wird, dass er korrekt unter dem vorherigen gerendert wird.
Off-Screen-Leinwände für Tracks und Highlights
Das Rendern von Canvas-Elementen ist relativ aufwendig. Wir möchten, dass das Insights-Panel flüssig und reaktionsschnell bleibt, während Sie damit arbeiten. Manchmal lässt es sich nicht vermeiden, das gesamte Canvas neu zu rendern, z. B. wenn Sie die Zoomstufe ändern. Das erneute Rendern von Canvas ist besonders aufwendig, da Sie nicht nur einen kleinen Teil neu rendern können. Sie müssen den gesamten Canvas löschen und neu zeichnen. Das ist anders als beim erneuten Rendern des DOM, bei dem Tools den minimalen Aufwand berechnen können, der erforderlich ist, und nicht alles entfernen und neu beginnen müssen.
Ein Bereich, in dem wir auf visuelle Probleme gestoßen sind, war die Hervorhebung. Wenn Sie den Mauszeiger auf Messwerte im Bereich bewegen, werden sie auf der Zeitachse hervorgehoben. Wenn Sie den Mauszeiger auf einen Insight für ein bestimmtes Ereignis bewegen, wird um dieses Ereignis ein blauer Rahmen gezeichnet.
Diese Funktion wurde zuerst implementiert, indem eine Mausbewegung über einem Element erkannt wurde, die eine Hervorhebung auslöst, und diese Hervorhebung dann direkt auf das Haupt-Canvas gezeichnet wurde. Das Problem tritt auf, wenn wir die Markierung entfernen müssen: Die einzige Möglichkeit besteht darin, alles neu zu zeichnen. Es ist unmöglich, nur den Bereich neu zu zeichnen, in dem sich die Markierung befand (nicht ohne große architektonische Änderungen). Das gesamte Canvas neu zu zeichnen, nur weil wir einen blauen Rahmen um ein Element entfernen möchten, erschien uns jedoch als übertrieben. Außerdem kam es zu visuellen Verzögerungen, wenn Sie die Maus schnell über verschiedene Elemente bewegten, um mehrere Hervorhebungen in schneller Folge auszulösen.
Um dieses Problem zu beheben, haben wir unsere Benutzeroberfläche in zwei Off-Screen-Canvas unterteilt: den „Haupt“-Canvas, auf dem Tracks gerendert werden, und den „Highlights“-Canvas, auf dem Highlights gezeichnet werden. Anschließend werden die einzelnen Canvas auf den Canvas kopiert, der dem Nutzer auf dem Bildschirm angezeigt wird. Wir können die Methode drawImage
für einen Canvas-Kontext verwenden, der einen anderen Canvas als Quelle verwenden kann.
Wenn wir so vorgehen, muss das Haupt-Canvas nicht neu gezeichnet werden, wenn ein Highlight entfernt wird. Stattdessen können wir das Canvas auf dem Bildschirm löschen und dann das Haupt-Canvas auf das sichtbare Canvas kopieren. Das Kopieren eines Canvas ist kostengünstig, das Zeichnen ist teuer. Wenn wir Highlights also auf einen separaten Canvas verschieben, vermeiden wir diese Kosten, wenn wir Highlights aktivieren und deaktivieren.
Umfassend getestetes Trace-Parsing
Einer der Vorteile der Entwicklung einer neuen Funktion von Grund auf ist, dass Sie die zuvor getroffenen technischen Entscheidungen überdenken und Verbesserungen vornehmen können. Wir wollten unseren Code explizit in zwei fast vollständig getrennte Teile aufteilen:
Analysieren Sie die Tracedatei und extrahieren Sie die erforderlichen Daten. Eine Reihe von Tracks rendern.
Durch die Trennung des Parsings (Teil 1) von der UI-Arbeit (Teil 2) konnten wir ein solides Parsing-System entwickeln. Jeder Trace wird durch eine Reihe von Handlern geleitet, die für verschiedene Aufgaben zuständig sind: Ein LayoutShiftHandler
berechnet alle Informationen, die wir für Layoutverschiebungen benötigen, und ein NetworkRequestsHandler
kümmert sich ausschließlich um das Abrufen von Netzwerkanfragen. Dieser explizite Parsing-Schritt, bei dem verschiedene Handler für verschiedene Teile des Traces zuständig sind, hat sich ebenfalls als vorteilhaft erwiesen: Das Parsen von Traces kann sehr kompliziert sein und es ist hilfreich, sich jeweils auf ein Problem zu konzentrieren.
Außerdem konnten wir das Parsen von Traces umfassend testen, indem wir Aufzeichnungen in DevTools erstellt, gespeichert und dann als Teil unserer Testsuite geladen haben. Das ist ein großer Vorteil, weil wir mit echten Traces testen können und nicht riesige Mengen an gefälschten Trace-Daten erstellen müssen, die veralten könnten.
Screenshot-Tests für die Canvas-Benutzeroberfläche
Um beim Thema Tests zu bleiben: Normalerweise testen wir unsere Frontend-Komponenten, indem wir sie im Browser rendern und dafür sorgen, dass sie sich wie erwartet verhalten. Wir können Klickereignisse senden, um Aktualisierungen auszulösen, und bestätigen, dass das von den Komponenten generierte DOM korrekt ist. Dieser Ansatz funktioniert gut für uns, stößt aber an seine Grenzen, wenn es darum geht, auf einem Canvas zu rendern. Es gibt keine Möglichkeit, einen Canvas zu untersuchen und festzustellen, was dort gezeichnet wird. Unser üblicher Ansatz, zuerst zu rendern und dann abzufragen, ist daher nicht geeignet.
Um eine gewisse Testabdeckung zu erreichen, haben wir uns für Screenshot-Tests entschieden. Bei jedem Test wird ein Canvas erstellt, der zu testende Track gerendert und dann ein Screenshot des Canvas-Elements aufgenommen. Dieser Screenshot wird dann in unserer Codebasis gespeichert und bei zukünftigen Testläufen mit dem generierten Screenshot verglichen. Wenn sich die Screenshots unterscheiden, schlägt der Test fehl. Außerdem stellen wir ein Flag zur Verfügung, mit dem der Test ausgeführt und ein Screenshot-Update erzwungen werden kann, wenn wir die Darstellung bewusst geändert haben und der Test aktualisiert werden muss.
Screenshot-Tests sind nicht perfekt und etwas ungenau. Sie können nur testen, ob die gesamte Komponente wie erwartet gerendert wird, anstatt spezifischere Behauptungen zu prüfen. Anfangs haben wir sie zu häufig verwendet, um sicherzustellen, dass jede einzelne Komponente (HTML oder Canvas) korrekt gerendert wird. Das hat unsere Testsuite drastisch verlangsamt und zu Problemen geführt, bei denen winzige, fast irrelevante UI-Anpassungen (z. B. subtile Farbänderungen oder das Hinzufügen von etwas Abstand zwischen Elementen) dazu führten, dass mehrere Screenshots fehlschlugen und aktualisiert werden mussten. Wir verwenden Screenshots jetzt weniger und nur noch für Canvas-basierte Komponenten. Diese Balance hat sich bisher bewährt.
Fazit
Die Entwicklung des neuen Bereichs „Leistungsstatistiken“ war für das Team eine sehr angenehme und lehrreiche Erfahrung. Wir haben viel über Trace-Dateien, die Arbeit mit Canvas und vieles mehr gelernt. Wir hoffen, dass Ihnen das neue Steuerfeld gefällt, und freuen uns auf Ihr Feedback.
Weitere Informationen zum Bereich „Leistungsstatistiken“ finden Sie unter Leistungsstatistiken: Umsetzbare Informationen zur Leistung Ihrer Website.
Vorschaukanäle herunterladen
Verwenden Sie Chrome Canary, Dev oder Beta als Standardbrowser für die Entwicklung. Über diese Preview-Channels haben Sie Zugriff auf die neuesten DevTools-Funktionen, können innovative Webplattform-APIs testen und Probleme auf Ihrer Website finden, bevor Ihre Nutzer sie entdecken.
Chrome-Entwicklertools-Team kontaktieren
Verwenden Sie die folgenden Optionen, um über die neuen Funktionen, Updates oder alles andere im Zusammenhang mit den Entwicklertools zu sprechen.
- Sie können uns Feedback und Funktionsanfragen unter crbug.com senden.
- Melden Sie ein DevTools-Problem in den Entwicklertools über das Weitere Optionen > Hilfe > DevTools-Problem melden.
- Senden Sie einen Tweet an @ChromeDevTools.
- Hinterlassen Sie Kommentare in den YouTube-Videos zu Neuerungen in den DevTools oder den YouTube-Videos mit DevTools-Tipps.