Verwendung der Paint Timing API

Avatar of Jeremy Wagner
Jeremy Wagner am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

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

Was `first-paint` aussehen könnte.

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

Wie ein `first-contentful-paint`-Ereignis aussehen könnte.

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

  1. Wir überprüfen einfach, ob das performance-Objekt im window-Objekt vorhanden ist. Dies verhindert, dass unser Code ausgeführt wird, wenn performance nicht verfügbar ist.
  2. Wir binden Code mit addEventListener an das load-Ereignis des window-Objekts, das ausgelöst wird, wenn die Seite und ihre Assets vollständig geladen sind.
  3. Im Code für das load-Ereignis verwenden wir die Methode getEntriesByType des performance-Objekts, um alle Ereignistypen von "paint" in einer Variablen namens paintMetrics abzurufen.
  4. 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 paintMetrics undefined ist und ob seine length größer als 0 ist.
  5. 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
In der Konsole angezeigte Paint-Timings.

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

  1. Wir prüfen auf die Existenz des PerformanceObserver-Objekts in window. Wenn PerformanceObserver nicht existiert, passiert nichts.
  2. Ein Promise wird erstellt. Im ersten Teil der Promise-Kette erstellen wir ein neues PerformanceObserver-Objekt und speichern es in der Variablen observer. Dieser Observer enthält einen Callback, der das Promise mit einer Liste von Paint-Zeitstempeln resolvet.
  3. Wir müssen diese Paint-Zeitstempel irgendwoher bekommen, richtig? Dort kommt die Methode observer ins 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".
  4. Wenn der Browser das Sammeln von "paint"-Ereignissen mit PerformanceObserver unterstützt, wird das Promise erfüllt und der nächste Teil der Kette beginnt, wo wir über die then-Methode Zugriff auf die Einträge durch die Methode getEntries der Variablen list haben. Dies erzeugt eine Konsolenausgabe, die dem vorherigen Beispiel ähnelt.
  5. Wenn der aktuelle Browser das Sammeln von "paint"-Ereignissen mit PerformanceObserver nicht unterstützt, bietet die catch-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.
  • PerformanceObserver hat 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!


Cover of Web Performance in Action

Jeremy Wagner ist der Autor von Web Performance in Action, jetzt erhältlich bei Manning Publications. Verwenden Sie den Promo-Code sswagner, um 42% zu sparen.

Schauen Sie ihn sich auf Twitter an: @malchata