Es ist eine großartige Zeit, um ein Web-Performance-Enthusiast zu sein, und die Einführung der Paint Timing API in Chrome 60 ist ein eindeutiger Beweis dafür. Die Paint Timing API ist eine weitere Ergänzung zur wachsenden Performance API, aber anstatt Seiten- und Ressourcen-Timings zu erfassen, ermöglicht Ihnen diese neue und experimentelle API, Metriken darüber zu erfassen, wann eine Seite zu malen beginnt.
Wenn Sie noch nicht mit den verschiedenen Performance-APIs experimentiert haben, kann es hilfreich sein, sich damit vertraut zu machen, da die Syntax dieser API viel mit diesen APIs (insbesondere der Resource Timing API) gemeinsam hat. Dennoch können Sie weiterlesen und auch dann etwas aus diesem Artikel mitnehmen, wenn Sie dies nicht tun. Bevor wir eintauchen, sprechen wir über das Malen und die spezifischen Zeitpunkte, die diese API sammelt.
Warum brauchen wir eine API zur Messung von Malzeiten?
Wenn Sie dies lesen, sind Sie wahrscheinlich mit dem Malen vertraut. Wenn nicht, ist es ein einfaches Konzept: Malen ist jede Aktivität des Browsers, bei der Pixel auf das Browserfenster gezeichnet werden. Es ist ein entscheidender Teil der Rendering-Pipeline. Wenn wir im Performance-Jargon über das Malen sprechen, beziehen wir uns oft auf den Zeitpunkt, an dem der Browser mit dem Malen einer Seite während des Ladens beginnt. Dieser Moment wird treffend als „Time to First Paint“ bezeichnet.
Warum ist diese Metrik wichtig zu kennen? Weil sie uns den frühesten möglichen Zeitpunkt signalisiert, an dem nach der Anforderung einer Seite durch einen Benutzer etwas erscheint. Während des Ladens einer Seite geschieht vieles, aber eines wissen wir: Je früher etwas für den Benutzer angezeigt wird, desto eher wird er erkennen, dass etwas geschieht. Ähnlich wie bei Ihrem LDL-Cholesterinspiegel beinhalten die meisten performance-orientierten Ziele die Senkung Ihrer Werte. Ohne zu wissen, wie Ihre Werte zunächst sind, kann das Erreichen dieser Ziele jedoch eine sinnlose Übung sein.
Glücklicherweise kann uns die Paint Timing API hierbei helfen. Diese API ermöglicht es Ihnen, mit JavaScript zu erfassen, wie schnell eine Seite für die Besucher Ihrer Website gemalt wird. Synthetische Tests in Programmen wie Lighthouse oder sitespeed.io sind großartig, da sie uns eine Basis für die Verbesserung der Performance von Websites bieten, für die wir verantwortlich sind. Aber all diese Tests finden im Vakuum statt. Sie sagen Ihnen nicht, wie Ihre Website für diejenigen performt, die sie tatsächlich nutzen.
Im Vergleich zu ähnlichen Performance-APIs ist die Paint Timing API stark vereinfacht. Sie liefert uns nur zwei Metriken:
first-paint: Dies ist wahrscheinlich das, was Sie denken. Der Zeitpunkt, an dem der Browser das erste Pixel auf der Seite gemalt hat. Es könnte so aussehen

first-contentful-paint: Dies ist etwas anders als first-paint, da es die Zeit erfasst, zu der das erste Stück Inhalt gemalt wurde, sei es Text, ein Bild oder etwas anderes als eine Variation von nicht-inhaltlicher Gestaltung. Dieses Szenario könnte so aussehen

Es ist wichtig zu betonen, dass diese beiden Zeitpunkte nicht immer so klar voneinander getrennt sind. Abhängig von der Client-Side-Architektur einer bestimmten Website können die Metriken first-paint und first-contentful-paint nicht abweichen. Bei schnelleren und leichteren Web-Erlebnissen sind sie oft nahezu (oder sogar genau) dasselbe. Auf größeren Websites, bei denen die Client-Side-Architektur viele Assets umfasst (und/oder bei langsameren Verbindungen), können diese beiden Metriken weiter auseinander liegen.
In jedem Fall wollen wir uns ansehen, wie diese API verwendet wird, die in Chrome 60 gelandet ist.
Ein einfacher Anwendungsfall
Es gibt ein paar Möglichkeiten, wie Sie diese API verwenden können. Der einfachste Weg ist, den Code an ein Ereignis zu binden, das einige Zeit nach dem ersten Malen auftritt. Der Grund, warum Sie dies an ein Ereignis binden möchten, anstatt es sofort auszuführen, ist, dass die Metriken tatsächlich verfügbar sind, wenn Sie versuchen, sie aus der API abzurufen. Nehmen Sie diesen Code zum Beispiel
if("performance" in window){
window.addEventListener("load", ()=>{
let paintMetrics = performance.getEntriesByType("paint");
if(paintMetrics !== undefined && paintMetrics.length > 0){
paintMetrics.forEach((paintMetric)=>{
console.log(`${paintMetric.name}: ${paintMetric.startTime}`);
});
}
});
}
Dieser Code tut Folgendes
- Wir überprüfen einfach, ob das
performance-Objekt imwindow-Objekt vorhanden ist. Dies verhindert, dass unser Code ausgeführt wird, wennperformancenicht verfügbar ist. - Wir binden Code mit
addEventListeneran dasload-Ereignis deswindow-Objekts, das ausgelöst wird, wenn die Seite und ihre Assets vollständig geladen sind. - Im Code für das
load-Ereignis verwenden wir die MethodegetEntriesByTypedesperformance-Objekts, um alle Ereignistypen von"paint"in einer Variablen namenspaintMetricsabzurufen. - Da nur Chrome 60 (und neuer) die Paint Timing API derzeit implementiert, müssen wir prüfen, ob Einträge zurückgegeben wurden. Dazu prüfen wir, ob
paintMetricsundefinedist und ob seinelengthgrößer als0ist. - Wenn wir diese Prüfungen bestanden haben, geben wir den Namen der Metrik und ihre Startzeit in die Konsole aus, was etwa so aussehen würde

Die Zeitangaben, die Sie im obigen Konsolen-Screenshot sehen, sind in Millisekunden. Von hier aus können Sie diese Metriken irgendwohin senden, um sie zu speichern und später zu analysieren.
Das funktioniert alles gut und schön, aber was ist, wenn wir Zugriff auf diese Metriken haben möchten, sobald der Browser sie sammelt? Dafür benötigen wir PerformanceObserver.
Erfassung von Paint-Metriken mit PerformanceObserver
Wenn Sie unbedingt und absolut sicherstellen müssen, dass Sie die Zeitstempel abrufen, sobald sie im Browser verfügbar sind, können Sie PerformanceObserver verwenden. Die Verwendung von PerformanceObserver kann knifflig sein, insbesondere wenn Sie sicherstellen möchten, dass Sie das Verhalten für Browser, die es nicht unterstützen, nicht beeinträchtigen, oder wenn Browser es tun, aber "paint"-Ereignisse nicht unterstützen. Letzteres Szenario ist für unsere Bemühungen hier relevant, da das Abfragen nicht unterstützter Ereignisse einen TypeError auslösen kann.
Da PerformanceObserver Metriken asynchron sammelt und protokolliert, ist unsere beste Option die Verwendung eines Promises, das uns hilft, asynchrone Dinge ohne das Callback-Chaos von früher zu handhaben. Nehmen Sie diesen Code zum Beispiel
if("PerformanceObserver" in window){
let observerPromise = new Promise((resolve, reject)=>{
let observer = new PerformanceObserver((list)=>{
resolve(list);
});
observer.observe({
entryTypes: ["paint"]
});
}).then((list)=>{
list.getEntries().forEach((entry)=>{
console.log(`${entry.name}: ${entry.startTime}`);
});
}).catch((error)=>{
console.warn(error);
});
}
Lassen Sie uns diesen Code durchgehen
- Wir prüfen auf die Existenz des
PerformanceObserver-Objekts inwindow. WennPerformanceObservernicht existiert, passiert nichts. - Ein
Promisewird erstellt. Im ersten Teil der Promise-Kette erstellen wir ein neuesPerformanceObserver-Objekt und speichern es in der Variablenobserver. Dieser Observer enthält einen Callback, der das Promise mit einer Liste von Paint-Zeitstempelnresolvet. - Wir müssen diese Paint-Zeitstempel irgendwoher bekommen, richtig? Dort kommt die Methode
observerins Spiel. Diese Methode erlaubt uns, festzulegen, welche Arten von Performance-Einträgen wir wollen. Da wir Painting-Ereignisse wollen, übergeben wir einfach ein Array mit einem Eintrags-Typ von"paint". - Wenn der Browser das Sammeln von
"paint"-Ereignissen mitPerformanceObserverunterstützt, wird das Promise erfüllt und der nächste Teil der Kette beginnt, wo wir über diethen-Methode Zugriff auf die Einträge durch die MethodegetEntriesder Variablenlisthaben. Dies erzeugt eine Konsolenausgabe, die dem vorherigen Beispiel ähnelt. - Wenn der aktuelle Browser das Sammeln von
"paint"-Ereignissen mitPerformanceObservernicht unterstützt, bietet diecatch-Methode Zugriff auf die Fehlermeldung. Von hier aus können wir mit diesen Informationen tun, was wir wollen.
Jetzt haben Sie eine Möglichkeit, Metriken asynchron zu sammeln, anstatt auf das Laden der Seite warten zu müssen. Ich persönlich bevorzuge die vorherige Methode, da der Code kürzer und lesbarer ist (zumindest für mich). Ich bin sicher, meine Methoden sind nicht die robustesten, aber sie veranschaulichen die Tatsache, dass Sie Paint-Zeitstempel im Browser auf eine vorhersehbare Weise sammeln können, die in älteren Browsern keine Fehler auslösen sollte.
Wofür würde ich das verwenden?
Hängt davon ab, was Sie erreichen wollen. Vielleicht möchten Sie sehen, wie schnell Ihre Website für echte Benutzer im Einsatz rendert. Vielleicht möchten Sie Daten für Forschungszwecke sammeln. Zum Zeitpunkt des Schreibens führe ich ein Bildqualitäts-Forschungsprojekt durch, das Teilnehmer darauf beurteilt, wie sie verlustbehaftete Bildqualität von JPEG- und WebP-Bildern wahrnehmen. Als Teil meiner Forschung verwende ich andere Timing-APIs, um Performance-bezogene Informationen zu sammeln, aber ich sammle auch Paint-Zeitstempel. Ich weiß nicht, ob diese Daten nützlich sein werden, aber das Sammeln und Analysieren im Tandem mit anderen Metriken könnte für meine Ergebnisse hilfreich sein. Wie Sie diese Daten verwenden, liegt wirklich bei Ihnen. Meiner bescheidenen Meinung nach ist es großartig, dass diese API existiert, und ich hoffe, dass mehr Browser sie bald implementieren werden.
Einige andere Dinge, die Sie vielleicht lesen möchten
Das Lesen dieses kurzen Beitrags hat Sie vielleicht an einigen anderen Teilen der breiteren Performance-Schnittstelle interessiert. Hier sind ein paar Artikel, die Sie sich ansehen können, wenn Ihre Neugier ausreichend geweckt wurde:
- Die Oberfläche dieser API wird mit der etablierten Resource Timing API geteilt, daher sollten Sie sich damit vertraut machen. Wenn Sie sich mit dem Code im Artikel wohlfühlen, können Sie sofort von dieser unglaublich wertvollen API profitieren.
- Obwohl diese API nicht viel Oberfläche mit der Navigation Timing API teilt, sollten Sie sich diese wirklich ansehen. Diese API ermöglicht es Ihnen, Timing-Daten darüber zu sammeln, wie schnell das HTML selbst geladen wird.
PerformanceObserverhat noch viel mehr zu bieten als das, was ich hier gezeigt habe. Sie können es verwenden, um Ressourcen-Timings und Benutzer-Timings zu erhalten. Lesen Sie hier darüber.- Apropos Benutzer-Timings, es gibt eine API dafür. Mit dieser API können Sie messen, wie lange bestimmte JavaScript-Aufgaben dauern, indem Sie hochpräzise Zeitstempel verwenden. Sie könnten dieses Werkzeug auch verwenden, um die Latenz bei der Interaktion von Benutzern mit der Seite zu messen.
Nachdem Sie sich nun mit dieser API auseinandergesetzt haben, machen Sie sich auf den Weg und sehen Sie, was sie (und andere APIs) für Sie auf Ihrer Suche nach einem schnelleren Web für Benutzer tun können!
Wie unterscheidet die Spezifikation zwischen first-paint und first-contentful-paint? Wie wird Inhalt bestimmt?
Laut https://github.com/WICG/paint-timing
"first-paint"-Einträge enthalten einen DOMHighResTimeStamp, der den Zeitpunkt meldet, an dem der Browser nach der Navigation zum ersten Mal gerendert hat. Dies schließt das Standard-Hintergrund-Painting aus, aber schließt nicht-standardmäßige Hintergrund-Paintings ein. Dies ist der erste wichtige Moment, der für Entwickler beim Laden von Seiten wichtig ist – wenn der Browser begonnen hat, die Seite zu rendern."first-contentful-paint"enthält einen DOMHighResTimestamp, der den Zeitpunkt meldet, an dem der Browser zum ersten Mal Text, Bilder (einschließlich Hintergrundbilder), nicht-weiße Canvas oder SVG gerendert hat. Dies schließt Text mit ausstehenden Web-Schriftarten ein. Dies ist das erste Mal, dass Benutzer mit dem Konsum von Seiteninhalten beginnen können.Ich hoffe, das hilft!
Toller Einführungsartikel, Jeremy!
Ich nehme an, beide Lösungen funktionieren in Chrome 60+ und in anderen Browsern, wenn diese APIs implementiert werden. Frage: Sind beide Lösungen in Bezug auf die Browserunterstützung gleichwertig oder ist eine der anderen vorzuziehen?
Vielen Dank.
Es kommt wirklich darauf an, was Sie erreichen wollen: Möchten Sie Metriken so schnell wie möglich sammeln und sofort handeln, wenn sie verfügbar sind? Verwenden Sie
PerformanceObserver. Wenn Sie es sich leisten können zu warten, sammeln Sie diese Metriken beimload-Ereignis (oder einem ähnlichen). Ich denke, das erstere ist einfacher zu schreiben und zu verstehen, und darauf habe ich mich verlassen, als ich Metriken auf meiner Bildumfrage-Website gesammelt habe. Wahrscheinlich wird jeder Browser, der Resource/Paint Timing APIs unterstützt, auchPerformanceObserverunterstützen, aber das Anhängen von Ereignissen mitaddEventListenerist sehr weit verbreitet.Viel Glück!