Navigations- und Ressourcen-Timings

Navigationstimings sind Metriken, die die Dokumentnavigationsereignisse eines Browsers messen. Ressourcen-Timings sind detaillierte Netzwerkzeitmessungen, die das Laden der Ressourcen einer Anwendung betreffen. Beide bieten dieselben schreibgeschützten Eigenschaften, aber die Navigationstiming misst die Zeiten des Hauptdokuments, während die Ressourcentiming die Zeiten für alle durch dieses Hauptdokument aufgerufenen Assets oder Ressourcen und deren angeforderte Ressourcen bereitstellt.

Die allgemeinen Leistungstimings unten sind zugunsten der Performance Entry API veraltet, die das Markieren und Messen von Zeiten entlang des Navigations- und Ressourcenladeprozesses ermöglicht. Obwohl veraltet, werden sie in allen Browsern unterstützt.

Leistungstimings

Die performanceTiming API, eine JavaScript-API zur Messung der Ladeleistung der angeforderten Seite, ist veraltet, wird jedoch in allen Browsern unterstützt. Sie wurde durch die performanceNavigationTiming API ersetzt.

Die Performance Timing API bot schreibgeschützte Zeiten in Millisekunden(ms), die beschreiben, zu welchem Zeitpunkt jeder Punkt im Seitenladeprozess erreicht wurde. Wie im folgenden Bild dargestellt, reicht der Navigationsprozess von navigationStart, unloadEventStart, unloadEventEnd, redirectStart, redirectEnd, fetchStart, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd, domLoading, domInteractive, domContentLoadedEventStart, domContentLoadedEventEnd, domComplete, loadEventStart und loadEventEnd.

Metriken der Navigationstiming-Ereignisse

Mit den oben genannten Metriken und einiger Mathematik können wir viele wichtige Metriken wie Time to first byte, Seitenladezeit, DNS-Lookup und ob die Verbindung sicher ist, berechnen.

Um die Zeit zu messen, die benötigt wird, um alle Schritte abzuschließen, bietet die Performance Timing API schreibgeschützte Messungen von Navigationstimings. Um die Timing unserer App zu betrachten und aufzuzeichnen, geben wir ein:

js
let time = window.performance.timing;

Wir können dann die Ergebnisse verwenden, um zu messen, wie gut unsere App läuft.

Eingabe von window.performance.timing in der Konsole listet alle Timings im PerformanceNavigationTiming-Interface auf

Die Reihenfolge ist:

Leistungstimings Details
[`navigationStart`](/de/docs/Web/API/PerformanceTiming/navigationStart) Wenn das Aufforderung zum Entladen im vorherigen Dokument im gleichen Browsing-Kontext endet. Wenn es kein vorheriges Dokument gibt, ist dieser Wert derselbe wie PerformanceTiming.fetchStart.
[`secureConnectionStart`](/de/docs/Web/API/PerformanceTiming/secureConnectionStart) Wenn der sichere Verbindungs-Handshake beginnt. Wenn keine solche Verbindung angefordert wird, wird 0 zurückgegeben.
[`redirectStart`](/de/docs/Web/API/PerformanceTiming/redirectStart) Wenn die erste HTTP-Umleitung startet. Wenn es keine Umleitung gibt oder eine der Umleitungen nicht von gleichem Ursprung ist, wird der zurückgegebene Wert 0 sein.
[`redirectEnd`](/de/docs/Web/API/PerformanceTiming/redirectEnd)

Wenn die letzte HTTP-Umleitung abgeschlossen ist, das heißt, wenn das letzte Byte der HTTP-Antwort empfangen wurde. Wenn es keine Umleitung gibt oder eine der Umleitungen nicht von gleichem Ursprung ist, wird der zurückgegebene Wert 0 sein.

[`connectEnd`](/de/docs/Web/API/PerformanceTiming/connectEnd) Wenn die Verbindung im Netzwerk geöffnet ist. Wenn die Transportschicht einen Fehler meldet und der Verbindungsaufbau erneut gestartet wird, wird die letzte Verbindungsaufbau-Endzeit angegeben. Wenn eine persistente Verbindung verwendet wird, ist der Wert derselbe wie PerformanceTiming.fetchStart. Eine Verbindung gilt als geöffnet, wenn alle sicheren Verbindungs-Handshakes oder SOCKS-Authentifizierungen abgeschlossen sind.
[`connectStart`](/de/docs/Web/API/PerformanceTiming/connectStart) Wenn die Anforderung zum Öffnen einer Verbindung an das Netzwerk gesendet wird. Wenn die Transportschicht einen Fehler meldet und der Verbindungsaufbau erneut gestartet wird, wird die letzte Verbindungsaufbau-Startzeit angegeben. Wenn eine persistente Verbindung verwendet wird, ist der Wert derselbe wie PerformanceTiming.fetchStart.
[`domainLookupEnd`](/de/docs/Web/API/PerformanceTiming/domainLookupEnd) Wenn die Domänensuche abgeschlossen ist. Wenn eine persistente Verbindung verwendet wird oder die Informationen in einem Cache oder einer lokalen Ressource gespeichert sind, ist der Wert derselbe wie PerformanceTiming.fetchStart.
[`domainLookupStart`](/de/docs/Web/API/PerformanceTiming/domainLookupStart) Wenn die Domänensuche beginnt. Wenn eine persistente Verbindung verwendet wird oder die Informationen in einem Cache oder einer lokalen Ressource gespeichert sind, ist der Wert derselbe wie PerformanceTiming.fetchStart.
[`fetchStart`](/de/docs/Web/API/PerformanceTiming/fetchStart) Wenn der Browser bereit ist, das Dokument mit einer HTTP-Anfrage abzurufen. Dieser Moment ist vor der Überprüfung eines Anwendungs-Caches.
[`requestStart`](/de/docs/Web/API/PerformanceTiming/requestStart) Wenn der Browser die Anfrage gesendet hat, um das eigentliche Dokument vom Server oder aus einem Cache zu erhalten. Wenn die Transportschicht nach dem Beginn der Anfrage fehlschlägt und die Verbindung erneut geöffnet wird, wird diese Eigenschaft auf die Zeit des neuen Anforderungskorrespondierenden eingestellt.
[`responseStart`](/de/docs/Web/API/PerformanceTiming/responseStart) Wenn der Browser das erste Byte der Antwort vom Server, aus einem Cache oder aus einer lokalen Ressource erhält.
[`responseEnd`](/de/docs/Web/API/PerformanceTiming/responseEnd) Wenn der Browser das letzte Byte der Antwort empfängt oder wenn die Verbindung geschlossen wird, wenn dies zuerst geschieht, vom Server, dem Cache oder von einer lokalen Ressource.
[`domLoading`](/de/docs/Web/API/PerformanceTiming/domLoading) Wenn der Parser mit seiner Arbeit beginnt, also wenn dessen [`Document.readyState`](/de/docs/Web/API/Document/readyState) sich auf 'loading' ändert und das entsprechende [`readystatechange`](/de/docs/Web/API/Document/readystatechange_event) Ereignis ausgelöst wird.
[`unloadEventStart`](/de/docs/Web/API/PerformanceTiming/unloadEventStart) Wenn das [`unload`](/de/docs/Web/API/Window/unload_event) Ereignis ausgelöst wurde, das die Zeit angibt, zu der das vorherige Dokument im Fenster begann, zu entladen. Wenn es kein vorheriges Dokument gibt oder wenn das vorherige Dokument oder eine der benötigten Umleitungen nicht denselben Ursprung hat, ist der zurückgegebene Wert 0.
[`unloadEventEnd`](/de/docs/Web/API/PerformanceTiming/unloadEventEnd) Wenn der unload Ereignishandler beendet ist. Wenn es kein vorheriges Dokument gibt oder wenn das vorherige Dokument oder eine der benötigten Umleitungen nicht denselben Ursprung hat, ist der zurückgegebene Wert 0.
[`domInteractive`](/de/docs/Web/API/PerformanceTiming/domInteractive) Wenn der Parser seine Arbeit am Hauptdokument beendet hat, also wenn dessen Document.readyState sich auf 'interactive' ändert und das entsprechende readystatechange Ereignis ausgelöst wird.
[`domContentLoadedEventStart`](/de/docs/Web/API/PerformanceTiming/domContentLoadedEventStart) Unmittelbar bevor der Parser das DOMContentLoaded Ereignis sendet, also direkt nachdem alle Skripte, die sofort nach dem Parsen ausgeführt werden müssen, ausgeführt wurden.
[`domContentLoadedEventEnd`](/de/docs/Web/API/PerformanceTiming/domContentLoadedEventEnd) Direkt nachdem alle Skripte, die so früh wie möglich in beliebiger Reihenfolge oder geordnet ausgeführt werden müssen, ausgeführt wurden.
[`domComplete`](/de/docs/Web/API/PerformanceTiming/domComplete) Wenn der Parser seine Arbeit am Hauptdokument beendet hat, also wenn dessen Document.readyState sich auf 'complete' ändert und das entsprechende readystatechange Ereignis ausgelöst wird.
[`loadEventStart`](/de/docs/Web/API/PerformanceTiming/loadEventStart) Wenn das load Ereignis für das aktuelle Dokument gesendet wurde. Wenn dieses Ereignis noch nicht gesendet wurde, wird 0 zurückgegeben.
[`loadEventEnd`](/de/docs/Web/API/PerformanceTiming/loadEventEnd) Wenn der load Ereignishandler beendet ist, also wenn das Ladeereignis abgeschlossen ist. Wenn dieses Ereignis noch nicht gesendet oder noch nicht abgeschlossen wurde, wird 0 zurückgegeben.

Berechnung der Timings

Wir können diese Werte verwenden, um spezifische interessante Timings zu messen:

js
const dns = time.domainLookupEnd - time.domainLookupStart;
const tcp = time.connectEnd - time.connectStart;
const tls = time.requestStart - time.secureConnectionStart;

Time to First Byte

Die Time to First Byte ist die Zeit zwischen dem navigationStart (Beginn der Navigation) und responseStart, (wenn das erste Byte der Antwort empfangen wird) verfügbar in der performanceTiming API:

js
const ttfb = time.responseStart - time.navigationStart;

Seite Ladezeit

Die Seitenladezeit ist die Zeit zwischen navigationStart und dem Zeitpunkt, an dem das Ladeereignis für das aktuelle Dokument gesendet wird. Sie sind nur in der performanceTiming API verfügbar.

js
let pageloadTime = time.loadEventStart - time.navigationStart;

DNS-Lookup-Zeit

Die DNS-Lookup-Zeit ist die Zeit zwischen domainLookupStart und domainLookupEnd. Diese sind sowohl in den performanceTiming als auch in den performanceNavigationTiming APIs verfügbar.

js
const dns = time.domainLookupEnd - time.domainLookupStart;

TCP

Die Zeit, die für den TCP-Handshake benötigt wird, ist die Zeit zwischen dem Beginn und Ende der Verbindung:

js
const tcp = time.connectEnd - time.connectStart;

TLS-Verhandlung

secureConnectionStart wird undefined sein, wenn nicht verfügbar, 0, wenn HTTPS nicht verwendet wird, oder ein Zeitstempel, wenn verfügbar und verwendet. Mit anderen Worten, wenn eine sichere Verbindung verwendet wurde, wird secureConnectionStart wahr sein, und die Zeit zwischen secureConnectionStart und requestStart wird größer als 0 sein.

js
const tls = time.requestStart - time.secureConnectionStart;

Performance Entry API

Die allgemeinen Leistungstimings oben sind veraltet, aber voll unterstützt. Wir haben jetzt die Performance Entry API, die das Markieren und Messen von Zeiten entlang des Navigations- und Ressourcenladeprozesses ermöglicht. Sie können auch Marken erstellen:

js
performance.getEntriesByType("navigation").forEach((navigation) => {
  console.dir(navigation);
});

performance.getEntriesByType("resource").forEach((resource) => {
  console.dir(resource);
});

performance.getEntriesByType("mark").forEach((mark) => {
  console.dir(mark);
});

performance.getEntriesByType("measure").forEach((measure) => {
  console.dir(measure);
});

performance.getEntriesByType("paint").forEach((paint) => {
  console.dir(paint);
});

performance.getEntriesByType("frame").forEach((frame) => {
  console.dir(frame);
});

In unterstützenden Browsern können Sie performance.getEntriesByType('paint') verwenden, um die Messung für first-paint und first-contentful-paint abzufragen. Wir verwenden performance.getEntriesByType('navigation') und performance.getEntriesByType('resource'), um die Navigations- und Ressourcentimings entsprechend abzufragen.

Wenn ein Benutzer eine Website oder Anwendung anfordert, um den Browser zu füllen, durchläuft der Benutzeragent eine Reihe von Schritten, einschließlich eines DNS-Lookups, TCP-Handshake und einer TLS-Verhandlung, bevor der Benutzeragent die eigentliche Anfrage sendet und die Server die angeforderten Assets zurückgeben. Der Browser analysiert dann den empfangenen Inhalt, baut die DOM, CSSOM, Zugänglichkeits- und Rendertrees auf und rendert schließlich die Seite. Sobald der Benutzeragent aufhört, das Dokument zu analysieren, wird die Dokumentbereitstellung auf interaktiv gesetzt. Wenn es verzögerte Skripte gibt, die analysiert werden müssen, wird dies jetzt durchgeführt und dann das DOMContentLoaded ausgelöst, wonach die Bereitschaft auf komplett gesetzt wird. Das Dokument kann jetzt Nachladeaufgaben ausführen, wonach das Dokument als vollständig geladen markiert wird.

js
const navigationTimings = performance.getEntriesByType("navigation");

performance.getEntriesByType('navigation') gibt ein Array von PerformanceEntry-Objekten für den Typ navigation zurück.

Das Ergebnis, wenn performance.getEntriesByType('navigation'); in der Konsole für dieses Dokument eingegeben wird

Vieles kann aus diesen Timings abgeleitet werden. Im obigen Bild sehen wir über die name-Eigenschaft, dass die Datei, die gemessen wird, dieses Dokument ist. Für den Rest dieser Erklärung verwenden wir die folgende Variable:

js
const timing = performance.getEntriesByType("navigation")[0];

Protokoll

Wir können das verwendete Protokoll überprüfen, indem wir abfragen:

js
const protocol = timing.nextHopProtocol;

Es gibt das Netzwerkprotokoll zurück, das zum Abrufen der Ressource verwendet wurde: in diesem Fall h2 für http/2.

Kompression

Um den prozentualen Einsparungsbetrag bei der Kompression zu ermitteln, teilen wir die transferSize durch die decodedBodySize und ziehen das von 100% ab. Wir sehen Einsparungen von über 74%.

js
const compressionSavings = 1 - timing.transferSize / timing.decodedBodySize;

Wir könnten auch verwenden

js
const compressionSavings = 1 - timing.encodedBodySize / timing.decodedBodySize;

aber die Verwendung von transferSize beinhaltet die Overhead-Bytes.

Zum Vergleich können wir den Netzwerk-Tab ansehen und sehen, dass wir 22,04 KB für eine unkomprimierte Dateigröße von 87,24 KB übertragen haben.

Ansicht der übertragenen Bytes und der Größe über den Netzwerk-Tab

Wenn wir die Berechnung mit diesen Zahlen durchführen, erhalten wir dasselbe Ergebnis: 1 - (22,04 / 87,24) = 0,747. Die Navigationstimings bieten uns eine Möglichkeit, die Übertragungssizinatorische und Bandbreiteneinsparungen programmatisch zu überprüfen.

Beachten Sie, dass dies die Größe nur für dieses einzelne Dokument ist: nur für diese Ressource allein, nicht für alle Ressourcen zusammen. Die Dauer, die Ladevorgänge und die DOM-bezogenen Timings beziehen sich jedoch auf die gesamte Navigation, nicht auf dieses einzelne Asset. Clientseitige Webanwendungen können schneller erscheinen als diese mit Übertragungsgrößen unter 10000 und decodierten Körpergrößen unter 30000, aber das bedeutet nicht, dass JavaScript, CSS oder Medienassets nicht zum Aufblähen beitragen. Das Überprüfen von Kompressionsverhältnissen ist wichtig, aber stellen Sie auch sicher, dass Sie die Dauer und die Zeit zwischen dem Ende des DOMContentLoaded-Ereignisses und dem vollständigen DOM überprüfen, da das Ausführen von JavaScript auf dem Main-Thread über längere Zeiträume zu einer nicht reagierenden Benutzeroberfläche führen kann.

Anforderungszeit

Die API bietet nicht jede Messung, die Sie möglicherweise benötigen. Zum Beispiel, wie lange dauert die Anfrage? Wir können die Messungen, die wir haben, verwenden, um unsere Antwort zu erhalten.

Um die Antwortzeit zu messen, ziehen Sie die Anforderungsstartzeit von der Antwortstartzeit ab. Der Anforderungsstart ist der Moment direkt bevor der Benutzeragent beginnt, die Ressource vom Server, von relevanten Anwendungs-Caches oder von lokalen Ressourcen anzufordern. Der Antwortstart ist die Zeit unmittelbar nachdem der HTTP-Parser des Benutzeragents das erste Byte der Antwort von relevanten Anwendungs-Caches, von lokalen Ressourcen oder vom Server erhält, was nach dem Empfang und der Verarbeitung der Anfrage geschieht.

js
const request = timing.responseStart - timing.requestStart;

Ladevorgangsdauer

Indem Sie den Zeitstempel unmittelbar bevor das Ladeereignis des aktuellen Dokuments ausgelöst wird, von dem Zeitpunkt abziehen, wenn das Ladeereignis des aktuellen Dokuments abgeschlossen ist, können Sie die Dauer des Ladevorgangs messen.

js
const load = timing.loadEventEnd - timing.loadEventStart;

DOMContentLoaded-Ereignis

Die Dauer des DOMContentLoaded-Ereignisses wird gemessen, indem der Zeitwert unmittelbar bevor der Benutzeragent das DOMContentLoaded-Ereignis auslöst, von dem Zeitwert abgezogen wird, der unmittelbar nach dem Abschluss des Ereignisses liegt. Das Halten dieser Zeit bei 50ms oder schneller hilft sicherzustellen, dass die Benutzeroberfläche ansprechend bleibt.

js
const DOMContentLoaded =
  timing.domContentLoadedEventEnd - timing.domContentLoadedEventStart;

Dauer

Uns wird die Dauer bereitgestellt. Die Dauer ist die Differenz zwischen den Eigenschaften PerformanceNavigationTiming.loadEventEnd und PerformanceEntry.startTime.

Die PerformanceNavigationTiming- Schnittstelle bietet auch Informationen darüber, welche Art von Navigation Sie messen, indem sie navigate, reload, back_forward oder prerender zurückgibt.

Ressourcentiming

Während das Navigationstiming zur Messung der Leistung der Hauptseite dient, in der Regel der HTML-Datei, über die alle anderen Assets angefordert werden, misst Ressourcentiming die Zeiten für einzelne Ressourcen, die Assets, die von der Hauptseite aufgerufen und von diesen Ressourcen angefordert werden. Viele der Messungen sind ähnlich: Es gibt eine DNS-Abfrage, einen TCP-Handshake und der Start der sicheren Verbindung wird pro Domäne einmal durchgeführt.

Grafik der Ressourcentiming-Zeitstempel

Das Hauptaugenmerk liegt auf jeder Ressource.

Siehe auch