Machen Sie sich mit den Grundlagen der Verwendung der Navigation und Resource Timing APIs vertraut, um die Ladeleistung vor Ort zu bewerten.
Wenn Sie die Verbindungsdrosselung im Netzwerkbereich in den Entwicklertools eines Browsers (oder in Lighthouse in Chrome) zur Bewertung der Ladeleistung verwendet haben, wissen Sie, wie praktisch diese Tools für die Leistungsoptimierung sind. Sie können die Auswirkungen von Leistungsoptimierungen schnell mit einer konsistenten und stabilen Basisverbindungsgeschwindigkeit messen. Das einzige Problem ist, dass es sich um synthetische Tests handelt, die zu Labdaten und nicht zu Felddaten führen.
Synthetische Tests sind nicht grundsätzlich schlecht. Sie sind jedoch nicht repräsentativ dafür, wie schnell Ihre Website für echte Nutzer geladen wird. Dafür sind Felddaten erforderlich, die Sie von den Navigation Timing und Resource Timing APIs erfassen können.
APIs für die Bewertung der Ladeleistung vor Ort
Navigation Timing und Resource Timing sind zwei ähnliche APIs mit erheblicher Überschneidung, die zwei verschiedene Dinge messen:
- Navigation Timing misst die Geschwindigkeit von Anfragen für HTML-Dokumente, d. h. Navigationsanfragen.
- Ressourcentiming misst die Geschwindigkeit von Anfragen für dokumentenabhängige Ressourcen wie CSS, JavaScript, Bilder usw.
Die Daten dieser APIs werden in einem Zwischenspeicher für Leistungseinträge verfügbar gemacht, auf den im Browser mit JavaScript zugegriffen werden kann. Es gibt mehrere Möglichkeiten, einen Leistungspuffer abzufragen, häufig wird jedoch performance.getEntriesByType
verwendet:
// Get Navigation Timing entries:
performance.getEntriesByType('navigation');
// Get Resource Timing entries:
performance.getEntriesByType('resource');
performance.getEntriesByType
akzeptiert einen String, der den Typ der Einträge beschreibt, die Sie aus dem Zwischenspeicher für Leistungseinträge abrufen möchten. 'navigation'
und 'resource'
rufen Zeiten für die Navigation Timing API bzw. die Resource Timing API ab.
Die Menge an Informationen, die diese APIs bereitstellen, kann überwältigend sein, aber sie sind der Schlüssel zur Messung der Ladeleistung vor Ort, da Sie diese Zeitangaben von Nutzern erfassen können, die Ihre Website besuchen.
Lebensdauer und Zeitpunkt einer Netzwerkanfrage
Das Erfassen und Analysieren von Navigations- und Ressourcenzeiten ist eine Art Archäologie, da Sie das flüchtige Leben einer Netzwerkanfrage nachträglich rekonstruieren. Manchmal hilft es, Konzepte zu visualisieren und bei Netzwerkanfragen die Entwicklertools des Browsers zu verwenden.
![Diagramm mit Netzwerktimings, wie in den Entwicklertools von Chrome dargestellt. Die Zeitangaben beziehen sich auf die Anfragewarteschlange, die Verbindungsverhandlung, die Anfrage selbst und die Antwort in farbcodierten Balken.](https://web.dev/static/articles/navigation-and-resource-timing/image/a-diagram-network-timing-fc676b860cafd.png?authuser=6&hl=de)
Der Lebenszyklus einer Netzwerkanfrage umfasst verschiedene Phasen, z. B. DNS-Lookup, Verbindungsaufbau, TLS-Verhandlung usw. Diese Zeitangaben werden als DOMHighResTimestamp
dargestellt. Je nach Browser kann der Detaillierungsgrad der Zeitangaben auf Mikrosekunden beschränkt oder auf Millisekunden aufgerundet werden. Sehen wir uns diese Phasen genauer an und wie sie mit dem Navigations-Timing und dem Ressourcen-Timing zusammenhängen.
DNS-Lookup
Wenn ein Nutzer eine URL aufruft, wird das Domain Name System (DNS) abgefragt, um die Domain in eine IP-Adresse umzuwandeln. Dieser Vorgang kann viel Zeit in Anspruch nehmen. Sie sollten auch Zeit in der Praxis messen. Navigation Timing und Resource Timing stellen zwei DNS-bezogene Timings bereit:
- Bei
domainLookupStart
beginnt der DNS-Lookup. - Bei
domainLookupEnd
endet der DNS-Lookup.
Sie können die gesamte DNS-Lookup-Zeit berechnen, indem Sie den Startmesswert vom Endmesswert subtrahieren:
// Measuring DNS lookup time
const [pageNav] = performance.getEntriesByType('navigation');
const totalLookupTime = pageNav.domainLookupEnd - pageNav.domainLookupStart;
Verbindungsverhandlung
Ein weiterer Faktor, der die Ladeleistung beeinflusst, ist die Verbindungsaushandlung. Hierbei handelt es sich um Latenzen beim Herstellen einer Verbindung zu einem Webserver. Wenn HTTPS verwendet wird, beinhaltet dieser Prozess auch die TLS-Verhandlungszeit. Die Verbindungsphase besteht aus drei Zeitpunkten:
- Bei
connectStart
beginnt der Browser, eine Verbindung zu einem Webserver herzustellen. secureConnectionStart
gibt an, wann der Kunde die TLS-Verhandlung beginnt.connectEnd
ist der Zeitpunkt, an dem die Verbindung zum Webserver hergestellt wurde.
Das Messen der Gesamtverbindungszeit ähnelt der Messung der gesamten DNS-Lookup-Zeit: Sie subtrahieren das Start- und das End-Timing. Es gibt jedoch noch eine zusätzliche secureConnectionStart
-Property, die möglicherweise 0
ist, wenn HTTPS nicht verwendet wird oder wenn die Verbindung dauerhaft ist. Wenn Sie die Verhandlungszeit für TLS messen möchten, müssen Sie Folgendes berücksichtigen:
// Quantifying total connection time
const [pageNav] = performance.getEntriesByType('navigation');
const connectionTime = pageNav.connectEnd - pageNav.connectStart;
let tlsTime = 0; // <-- Assume 0 to start with
// Was there TLS negotiation?
if (pageNav.secureConnectionStart > 0) {
// Awesome! Calculate it!
tlsTime = pageNav.connectEnd - pageNav.secureConnectionStart;
}
Sobald der DNS-Lookup und die Verbindungsverhandlung beendet sind, kommen die Zeiten im Zusammenhang mit dem Abrufen von Dokumenten und ihren abhängigen Ressourcen ins Spiel.
Anfragen und Antworten
Die Ladeleistung wird von zwei Faktoren beeinflusst:
- Extrinsische Faktoren:z. B. Latenz und Bandbreite. Über die Auswahl eines Hosting-Unternehmens und eines CDN hinaus liegt die Entscheidung größtenteils nicht in unserer Kontrolle, da die Nutzer von überall aus auf das Internet zugreifen können.
- Intrinsische Faktoren:Dazu gehören z. B. server- und clientseitige Architekturen sowie die Ressourcengröße und unsere Optimierungsfähigkeit für diese Dinge, auf die wir Einfluss haben.
Beide Faktoren beeinflussen die Ladeleistung. Das mit diesen Faktoren verbundene Timing ist von entscheidender Bedeutung, da sie beschreiben, wie lange der Download von Ressourcen dauert. Sowohl „Navigation Timing“ als auch „Resource Timing“ beschreiben die Ladeleistung mit den folgenden Messwerten:
fetchStart
gibt an, wann der Browser mit dem Abrufen einer Ressource (Ressourcentiming) oder eines Dokuments für eine Navigationsanfrage (Navigationstiming) beginnt. Dies geht der eigentlichen Anfrage voraus und ist der Punkt, an dem der Browser den Cache prüft (z. B. HTTP- undCache
-Instanzen).workerStart
gibt an, wann die Verarbeitung einer Anfrage im Event-Handlerfetch
eines Service Workers beginnt. Der Wert ist0
, wenn die aktuelle Seite von keinem Service Worker gesteuert wird.- Bei
requestStart
stellt der Browser die Anfrage. - Bei
responseStart
kommt das erste Byte der Antwort an. - Bei
responseEnd
kommt das letzte Byte der Antwort an.
Mit diesen Zeitangaben können Sie mehrere Aspekte der Ladeleistung messen, z. B. die Cache-Suche innerhalb eines Service Workers und die Downloadzeit:
// Cache seek plus response time of the current document
const [pageNav] = performance.getEntriesByType('navigation');
const fetchTime = pageNav.responseEnd - pageNav.fetchStart;
// Service worker time plus response time
let workerTime = 0;
if (pageNav.workerStart > 0) {
workerTime = pageNav.responseEnd - pageNav.workerStart;
}
Sie können auch andere Aspekte der Anfrage-/Antwortlatenz messen:
const [pageNav] = performance.getEntriesByType('navigation');
// Request time only (excluding redirects, DNS, and connection/TLS time)
const requestTime = pageNav.responseStart - pageNav.requestStart;
// Response time only (download)
const responseTime = pageNav.responseEnd - pageNav.responseStart;
// Request + response time
const requestResponseTime = pageNav.responseEnd - pageNav.requestStart;
Weitere mögliche Messungen
Navigation Timing und Resource Timing sind für mehr als das, was in den Beispielen oben beschrieben nützlich ist, nützlich. Hier sind einige andere Situationen mit relevanten Zeiten, die es sich lohnen könnten, sie sich genauer anzusehen:
- Seitenweiterleitungen:Weiterleitungen sind eine übersehene Ursache zusätzlicher Latenz, insbesondere bei Weiterleitungsketten. Die Latenz wird auf verschiedene Weise hinzugefügt, z. B. durch HTTP-zu-HTTP-Hops sowie 302/nicht zwischengespeicherte 301-Weiterleitungen. Die
redirectStart
-,redirectEnd
- undredirectCount
-Timings sind hilfreich, um die Weiterleitungslatenz zu beurteilen. - Entladen von Dokumenten:Auf Seiten, auf denen Code in einem
unload
-Event-Handler ausgeführt wird, muss der Browser diesen Code ausführen, bevor er die nächste Seite aufrufen kann.unloadEventStart
undunloadEventEnd
messen das Entladen von Dokumenten. - Dokumentverarbeitung: Die Verarbeitungszeit von Dokumenten kann nur dann sehr lang sein, wenn Ihre Website sehr große HTML-Nutzlasten sendet. Wenn dies auf deine Situation zutrifft, könnten die Zeitangaben für
domInteractive
,domContentLoadedEventStart
,domContentLoadedEventEnd
unddomComplete
von Interesse sein.
Timings im Anwendungscode erhalten
Für alle bisher gezeigten Beispiele wird performance.getEntriesByType
verwendet. Es gibt jedoch auch andere Möglichkeiten, den Zwischenspeicher für Leistungseinträge abzufragen, z. B. performance.getEntriesByName
und performance.getEntries
. Diese Methoden sind in Ordnung, wenn nur die Lichtanalyse erforderlich ist. In anderen Situationen können sie jedoch zu einer übermäßigen Hauptthread-Arbeit führen, indem sie über eine große Anzahl von Einträgen iterieren oder sogar wiederholt den Leistungspuffer abfragen, um neue Einträge zu finden.
Zum Erfassen von Einträgen aus dem Zwischenspeicher für Leistungseinträge wird empfohlen, einen PerformanceObserver
zu verwenden. PerformanceObserver
wartet auf Leistungseinträge und stellt sie bereit, wenn sie dem Zwischenspeicher hinzugefügt werden:
// Create the performance observer:
const perfObserver = new PerformanceObserver((observedEntries) => {
// Get all resource entries collected so far:
const entries = observedEntries.getEntries();
// Iterate over entries:
for (let i = 0; i < entries.length; i++) {
// Do the work!
}
});
// Run the observer for Navigation Timing entries:
perfObserver.observe({
type: 'navigation',
buffered: true
});
// Run the observer for Resource Timing entries:
perfObserver.observe({
type: 'resource',
buffered: true
});
Diese Methode zum Erfassen von Zeitangaben mag im Vergleich zum direkten Zugriff auf den Zwischenspeicher für Leistungseinträge etwas unangenehm wirken. Es ist jedoch besser, den Hauptthread mit Aufgaben zu verknüpfen, die keinen kritischen und nutzerorientierten Zweck erfüllen.
Zuhause anrufen
Nachdem Sie alle benötigten Zeitangaben erfasst haben, können Sie sie zur weiteren Analyse an einen Endpunkt senden. Dafür gibt es zwei Möglichkeiten: mit navigator.sendBeacon
oder mit fetch
, bei dem die Option keepalive
festgelegt ist. Bei beiden Methoden wird eine Anfrage nicht blockierend an einen angegebenen Endpunkt gesendet. Die Anfrage wird so in die Warteschlange gestellt, dass die aktuelle Seitensitzung bei Bedarf überschritten wird:
// Caution: If you have lots of performance entries, don't
// do this. This is an example for illustrative purposes.
const data = JSON.stringify(performance.getEntries()));
// The endpoint to transmit the encoded data to
const endpoint = '/analytics';
// Check for fetch keepalive support
if ('keepalive' in Request.prototype) {
fetch(endpoint, {
method: 'POST',
body: data,
keepalive: true,
headers: {
'Content-Type': 'application/json'
}
});
} else if ('sendBeacon' in navigator) {
// Use sendBeacon as a fallback
navigator.sendBeacon(endpoint, data);
}
In diesem Beispiel kommt der JSON-String in einer POST
-Nutzlast an, die Sie nach Bedarf in einem Anwendungs-Back-End decodieren und verarbeiten/speichern können.
Zusammenfassung
Nachdem Sie Metriken erfasst haben, müssen Sie herausfinden, wie Sie diese Felddaten analysieren. Bei der Analyse von Felddaten sollten Sie einige allgemeine Regeln beachten, um aussagekräftige Schlüsse zu ziehen:
- Vermeiden Sie Durchschnittswerte, da diese nicht repräsentativ für die Nutzererfahrung sind und durch Ausreißer verfälscht werden können.
- Abhängig von Perzentilen. In Datasets mit zeitbasierten Leistungsmesswerten gilt: Je niedriger der Wert, desto besser. Wenn Sie also niedrige Perzentile priorisieren, achten Sie nur auf die schnellsten Websitevarianten.
- Priorisieren Sie die Long Tail von Werten. Wenn Sie Websitevarianten ab dem 75. Perzentil priorisieren, fokussieren Sie sich auf die langsamsten Websites.
Dieser Leitfaden stellt keine umfassende Ressource zur Navigation oder zum Ressourcentiming dar, sondern stellt einen Ausgangspunkt dar. Nachfolgend finden Sie einige zusätzliche Ressourcen, die hilfreich sein könnten:
- Spezifikationen für das Navigationstiming:
- Spezifikation für Ressourcentiming.
- ResourceTiming in der Praxis.
- Navigation Timing API (MDN)
- Resource Timing API (MDN)
Mit diesen APIs und den von ihnen bereitgestellten Daten sind Sie besser gerüstet, um zu verstehen, wie die Ladeleistung von echten Nutzern wahrgenommen wird. Dies gibt Ihnen mehr Vertrauen bei der Diagnose und Behebung von Problemen mit der Ladeleistung vor Ort.