Entdecken Sie, wie die Performance Observer API eine leistungsstarke, nicht-intrusive Methode zur Überwachung der Web-Performance zur Laufzeit bietet, Core Web Vitals verfolgt und die Benutzererfahrung optimiert.
Web-Performance freisetzen: Ein Deep Dive in die Performance Observer API
In der heutigen schnelllebigen digitalen Welt ist Web-Performance kein Luxus mehr, sondern eine Notwendigkeit. Eine langsame oder nicht reagierende Website kann zu Benutzerfrustration, höheren Absprungraten und direkten negativen Auswirkungen auf Geschäftsziele führen, sei es Umsatz, Werbeeinnahmen oder Benutzerengagement. Jahrelang haben sich Entwickler auf Tools verlassen, die die Performance zu einem bestimmten Zeitpunkt messen, typischerweise während des initialen Seitenladens. Obwohl dies nützlich ist, verfehlt dieser Ansatz einen entscheidenden Teil der Geschichte: die gesamte Erfahrung des Benutzers, während er mit der Seite interagiert. Hier kommt die Laufzeit-Performance-Überwachung ins Spiel, und ihr mächtigstes Werkzeug ist die Performance Observer API.
Traditionelle Methoden beinhalten oft das Abfragen von Performance-Daten mit Funktionen wie performance.getEntries(). Dies kann ineffizient sein, anfällig dafür, entscheidende Ereignisse zu verpassen, die zwischen den Abfragen stattfinden, und kann sogar den Performance-Overhead erhöhen, den es zu messen versucht. Die Performance Observer API revolutioniert diesen Prozess, indem sie einen asynchronen, geringen Overhead-Mechanismus bereitstellt, um Performance-Ereignisse zu abonnieren, sobald sie auftreten. Dieser Leitfaden führt Sie auf einen Deep Dive in diese essentielle API und zeigt Ihnen, wie Sie ihre Leistung nutzen können, um Core Web Vitals zu überwachen, Engpässe zu identifizieren und letztendlich schnellere, angenehmere Web-Erlebnisse für ein globales Publikum zu erstellen.
Was ist die Performance Observer API?
Im Kern ist die Performance Observer API eine Schnittstelle, die eine Möglichkeit bietet, Performance-Messereignisse, sogenannte Performance-Einträge, zu beobachten und zu sammeln. Stellen Sie es sich als einen dedizierten Listener für performancebezogene Aktivitäten im Browser vor. Anstatt den Browser aktiv zu fragen: „Ist schon etwas passiert?“, teilt Ihnen der Browser proaktiv mit: „Ein neues Performance-Ereignis ist gerade aufgetreten! Hier sind die Details.“
Dies wird durch ein Observer-Muster erreicht. Sie erstellen eine Observer-Instanz, teilen ihr mit, welche Arten von Performance-Ereignissen Sie interessieren (z. B. große Paints, Benutzereingaben, Layout-Verschiebungen), und stellen eine Callback-Funktion bereit. Wenn ein neues Ereignis eines bestimmten Typs in der Performance-Timeline des Browsers aufgezeichnet wird, wird Ihre Callback-Funktion mit einer Liste der neuen Einträge aufgerufen. Dieses asynchrone, Push-basierte Modell ist weitaus effizienter und zuverlässiger als das ältere Pull-basierte Modell des wiederholten Aufrufens von performance.getEntries().
Der alte Weg vs. der neue Weg
Um die Innovation von Performance Observer zu würdigen, vergleichen wir die beiden Ansätze:
- Der alte Weg (Polling): Sie könnten setTimeout oder requestAnimationFrame verwenden, um in regelmäßigen Abständen performance.getEntriesByName('my-metric') aufzurufen, um zu sehen, ob Ihre Metrik aufgezeichnet wurde. Dies ist problematisch, da Sie möglicherweise zu spät prüfen und das Ereignis verpassen oder zu häufig prüfen und CPU-Zyklen verschwenden. Sie riskieren auch, den Performance-Puffer des Browsers zu füllen, wenn Sie Einträge nicht regelmäßig löschen.
- Der neue Weg (Observing): Sie richten einen PerformanceObserver einmal ein. Er sitzt unauffällig im Hintergrund und verbraucht nur minimale Ressourcen. Sobald ein relevanter Performance-Eintrag aufgezeichnet wird – egal ob eine Millisekunde nach dem Laden der Seite oder zehn Minuten in der Sitzung eines Benutzers – wird Ihr Code sofort benachrichtigt. Dadurch wird sichergestellt, dass Sie kein Ereignis verpassen und Ihr Überwachungscode so effizient wie möglich ist.
Warum Sie Performance Observer verwenden sollten
Die Integration der Performance Observer API in Ihren Entwicklungs-Workflow bietet eine Vielzahl von Vorteilen, die für moderne Webanwendungen, die eine globale Reichweite anstreben, von entscheidender Bedeutung sind.
- Nicht-intrusive Überwachung: Der Callback des Observers wird typischerweise während der Leerlaufzeiten ausgeführt, wodurch sichergestellt wird, dass Ihr Performance-Überwachungscode die Benutzererfahrung nicht beeinträchtigt oder den Haupt-Thread blockiert. Es ist darauf ausgelegt, leichtgewichtig zu sein und einen vernachlässigbaren Performance-Footprint zu haben.
- Umfassende Laufzeitdaten: Das Web ist dynamisch. Performance-Probleme treten nicht nur zur Ladezeit auf. Ein Benutzer kann eine komplexe Animation auslösen, mehr Inhalte durch Scrollen laden oder mit einer ressourcenintensiven Komponente lange nach dem Laden der ersten Seite interagieren. Performance Observer erfasst diese Laufzeitereignisse und gibt Ihnen ein vollständiges Bild der gesamten Benutzersitzung.
- Zukunftssicher und standardisiert: Es ist der von W3C empfohlene Standard für das Sammeln von Performance-Daten. Neue Performance-Metriken und APIs sind so konzipiert, dass sie sich integrieren lassen, was es zu einer nachhaltigen und zukunftsorientierten Wahl für Ihre Projekte macht.
- Die Grundlage des Real User Monitoring (RUM): Um wirklich zu verstehen, wie Ihre Website für Benutzer in verschiedenen Ländern, auf verschiedenen Geräten und unter verschiedenen Netzwerkbedingungen funktioniert, benötigen Sie Daten aus realen Sitzungen. Performance Observer ist das ideale Werkzeug zum Aufbau einer robusten RUM-Lösung, mit der Sie wichtige Metriken sammeln und an einen Analysedienst zur Aggregation und Analyse senden können.
- Eliminiert Race Conditions: Mit Polling versuchen Sie möglicherweise, auf einen Performance-Eintrag zuzugreifen, bevor er aufgezeichnet wurde. Das Observer-Modell eliminiert diese Race Condition vollständig, da Ihr Code erst ausgeführt wird, nachdem der Eintrag verfügbar ist.
Erste Schritte: Die Grundlagen des Performance Observers
Die Verwendung der API ist unkompliziert. Der Prozess umfasst drei Hauptschritte: Erstellen eines Observers, Definieren eines Callbacks und Anweisen des Observers, wonach er suchen soll.
1. Erstellen eines Observers mit einem Callback
Zuerst instanziieren Sie ein PerformanceObserver-Objekt und übergeben ihm eine Callback-Funktion. Diese Funktion wird ausgeführt, wenn neue Einträge erkannt werden.
const observer = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { console.log('Entry Type:', entry.entryType); console.log('Entry Name:', entry.name); console.log('Start Time:', entry.startTime); console.log('Duration:', entry.duration); } });
Der Callback empfängt ein PerformanceObserverEntryList-Objekt. Sie können die Methode getEntries() für diese Liste aufrufen, um ein Array aller neu beobachteten Performance-Einträge abzurufen.
2. Beobachten bestimmter Eintragstypen
Ein Observer tut nichts, bis Sie ihm sagen, was er überwachen soll. Sie tun dies mit der Methode .observe(). Diese Methode akzeptiert ein Objekt mit der Eigenschaft entryTypes (oder in einigen modernen Fällen nur type für einen einzelnen Typ), das ein Array von Zeichenfolgen ist, die die Performance-Eintragstypen darstellen, an denen Sie interessiert sind.
// Beginne mit der Beobachtung von zwei Arten von Einträgen observer.observe({ entryTypes: ['mark', 'measure'] });
Einige der gebräuchlichsten Eintragstypen sind:
- 'resource': Details zu Netzwerkanforderungen für Assets wie Skripte, Bilder und Stylesheets.
- 'paint': Timing für First-Paint und First-Contentful-Paint.
- 'largest-contentful-paint': Die Core Web Vital-Metrik für die wahrgenommene Ladegeschwindigkeit.
- 'layout-shift': Die Core Web Vital-Metrik für visuelle Stabilität.
- 'first-input': Informationen über die erste Benutzerinteraktion, verwendet für die First Input Delay Core Web Vital.
- 'longtask': Identifiziert Aufgaben im Haupt-Thread, die länger als 50 Millisekunden dauern und Unreaktionsfähigkeit verursachen können.
- 'mark' & 'measure': Benutzerdefinierte Marker und Messungen, die Sie in Ihrem eigenen Code mit der User Timing API definieren.
3. Stoppen des Observers
Wenn Sie keine Daten mehr sammeln müssen, ist es eine gute Praxis, den Observer zu trennen, um Ressourcen freizugeben.
observer.disconnect();
Praktische Anwendungsfälle: Überwachung der Core Web Vitals
Core Web Vitals sind eine Reihe spezifischer Faktoren, die Google für die allgemeine Benutzererfahrung einer Webseite als wichtig erachtet. Die Überwachung ist eine der leistungsstärksten Anwendungen der Performance Observer API. Sehen wir uns an, wie man jeden einzelnen misst.
Überwachung von Largest Contentful Paint (LCP)
LCP misst die Ladeperformance. Es markiert den Punkt in der Timeline des Seitenladens, an dem der Hauptinhalt wahrscheinlich geladen wurde. Ein gutes LCP-Ergebnis ist 2,5 Sekunden oder weniger.
Das LCP-Element kann sich während des Ladens der Seite ändern. Anfangs könnte eine Überschrift das LCP-Element sein, aber später könnte ein größeres Bild geladen werden und zum neuen LCP-Element werden. Aus diesem Grund ist ein Performance Observer perfekt – er benachrichtigt Sie über jeden potenziellen LCP-Kandidaten, sobald er gerendert wird.
// Beobachten Sie LCP und protokollieren Sie den endgültigen Wert let lcpValue = 0; const lcpObserver = new PerformanceObserver((entryList) => { const entries = entryList.getEntries(); // Der letzte Eintrag ist der aktuellste LCP-Kandidat const lastEntry = entries[entries.length - 1]; lcpValue = lastEntry.startTime; console.log(`LCP aktualisiert: ${lcpValue.toFixed(2)}ms`, lastEntry.element); }); lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true }); // Es ist eine gute Praxis, den Observer zu trennen, nachdem der Benutzer interagiert hat, // da Interaktionen dazu führen können, dass keine neuen LCP-Kandidaten mehr gesendet werden. // window.addEventListener('beforeunload', () => lcpObserver.disconnect());
Beachten Sie die Verwendung von buffered: true. Dies ist eine entscheidende Option, die den Observer anweist, Einträge einzubeziehen, die *bevor* die Methode observe() aufgerufen wurde, aufgezeichnet wurden. Dies verhindert, dass Sie ein frühes LCP-Ereignis verpassen.
Überwachung von First Input Delay (FID) und Interaction to Next Paint (INP)
Diese Metriken messen die Interaktivität. Sie quantifizieren die Erfahrung des Benutzers, wenn er zum ersten Mal mit der Seite interagiert.
First Input Delay (FID) misst die Zeit von dem Zeitpunkt, an dem ein Benutzer zum ersten Mal mit einer Seite interagiert (z. B. auf eine Schaltfläche klickt), bis zu dem Zeitpunkt, an dem der Browser tatsächlich damit beginnen kann, Ereignis-Handler als Reaktion auf diese Interaktion zu verarbeiten. Ein gutes FID ist 100 Millisekunden oder weniger.
Interaction to Next Paint (INP) ist eine neuere, umfassendere Metrik, die FID im März 2024 als Core Web Vital ersetzt hat. Während FID nur die *Verzögerung* der *ersten* Interaktion misst, beurteilt INP die *gesamte Latenz* *aller* Benutzerinteraktionen während der gesamten Lebensdauer der Seite und meldet die schlechteste. Dies gibt ein besseres Bild der Gesamtansprechbarkeit. Ein gutes INP ist 200 Millisekunden oder weniger.
Sie können FID mithilfe des Eintrags-Typs „first-input“ überwachen:
// FID beobachten const fidObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { const fid = entry.processingStart - entry.startTime; console.log(`FID: ${fid.toFixed(2)}ms`); // Trennen Sie nach dem Bericht der ersten Eingabe fidObserver.disconnect(); } }); fidObserver.observe({ type: 'first-input', buffered: true });
Die Überwachung von INP ist etwas aufwändiger, da sie die gesamte Dauer eines Ereignisses betrachtet. Sie beobachten den Eintragstyp „event“ und berechnen die Dauer, wobei Sie den längsten Wert verfolgen.
// Vereinfachtes INP-Überwachungsbeispiel let worstInp = 0; const inpObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { // Der INP ist die Dauer des Ereignisses const inp = entry.duration; // Wir interessieren uns nur für Interaktionen, die länger als die aktuelle schlechteste sind if (inp > worstInp) { worstInp = inp; console.log(`Neues schlechtestes INP: ${worstInp.toFixed(2)}ms`); } } }); inpObserver.observe({ type: 'event', durationThreshold: 16, buffered: true }); // durationThreshold hilft, sehr kurze, wahrscheinlich unbedeutende Ereignisse herauszufiltern.
Überwachung von Cumulative Layout Shift (CLS)
CLS misst die visuelle Stabilität. Es hilft, zu quantifizieren, wie oft Benutzer unerwartete Layout-Verschiebungen erleben – eine frustrierende Erfahrung, bei der sich Inhalte auf der Seite ohne Vorwarnung bewegen. Ein gutes CLS-Ergebnis ist 0,1 oder weniger.
Das Ergebnis ist eine Aggregation aller einzelnen Layout-Verschiebungs-Ergebnisse. Ein Performance Observer ist hier unerlässlich, da er jede Verschiebung meldet, sobald sie auftritt.
// Beobachten und berechnen Sie das Gesamt-CLS-Ergebnis let clsScore = 0; const clsObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { // Wir wollen keine Verschiebungen zählen, die durch Benutzereingaben verursacht wurden if (!entry.hadRecentInput) { clsScore += entry.value; console.log(`Aktuelles CLS-Ergebnis: ${clsScore.toFixed(4)}`); } } }); clsObserver.observe({ type: 'layout-shift', buffered: true });
Die Eigenschaft hadRecentInput ist wichtig. Sie hilft Ihnen, legitime Layout-Verschiebungen herauszufiltern, die als Reaktion auf eine Benutzeraktion (z. B. das Klicken auf eine Schaltfläche, die ein Menü erweitert) auftreten, die nicht zum CLS-Ergebnis gezählt werden sollten.
Über Core Web Vitals hinaus: Andere leistungsstarke Eintragstypen
Während Core Web Vitals ein großartiger Ausgangspunkt sind, kann Performance Observer noch viel mehr überwachen. Hier sind einige andere unglaublich nützliche Eintragstypen.
Verfolgung langer Aufgaben (`longtask`)
Die Long Tasks API macht Aufgaben verfügbar, die den Haupt-Thread für 50 Millisekunden oder länger belegen. Diese sind problematisch, da die Seite, während der Haupt-Thread beschäftigt ist, nicht auf Benutzereingaben reagieren kann, was zu einer trägen oder eingefrorenen Erfahrung führt. Die Identifizierung dieser Aufgaben ist der Schlüssel zur Verbesserung von INP.
// Lange Aufgaben beobachten const longTaskObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { console.log(`Lange Aufgabe erkannt: ${entry.duration.toFixed(2)}ms`); // Die Eigenschaft „attribution“ kann Ihnen manchmal sagen, was die lange Aufgabe verursacht hat console.log('Attribution:', entry.attribution); } }); longTaskObserver.observe({ type: 'longtask', buffered: true });
Analyse von Ressourcen-Timings (`resource`)
Das Verständnis, wie Ihre Assets geladen werden, ist grundlegend für die Leistungsoptimierung. Der Eintragstyp „resource“ liefert Ihnen detaillierte Netzwerk-Timing-Daten für jede Ressource auf Ihrer Seite, einschließlich DNS-Lookup, TCP-Verbindung und Inhalts-Download-Zeiten.
// Ressourcen-Timings beobachten const resourceObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { // Finden wir langsam ladende Bilder if (entry.initiatorType === 'img' && entry.duration > 500) { console.warn(`Langsam ladendes Bild erkannt: ${entry.name}`, `Dauer: ${entry.duration.toFixed(2)}ms`); } } }); // Die Verwendung von „buffered: true“ ist fast immer für Ressourcen-Timings erforderlich, // um Assets abzufangen, die geladen wurden, bevor dieses Skript ausgeführt wurde. resourceObserver.observe({ type: 'resource', buffered: true });
Messen benutzerdefinierter Performance-Markierungen (`mark` und `measure`)
Manchmal müssen Sie die Performance von anwendungsspezifischer Logik messen. Die User Timing API ermöglicht es Ihnen, benutzerdefinierte Zeitstempel zu erstellen und die Dauer zwischen ihnen zu messen.
- performance.mark('start-operation'): Erstellt einen Zeitstempel namens 'start-operation'.
- performance.mark('end-operation'): Erstellt einen weiteren Zeitstempel.
- performance.measure('my-operation', 'start-operation', 'end-operation'): Erstellt eine Messung zwischen den beiden Markierungen.
Performance Observer kann diese benutzerdefinierten „mark“- und „measure“-Einträge abhören, was sich perfekt zum Sammeln von Timing-Daten für Dinge wie Komponenten-Renderzeiten in einem JavaScript-Framework oder die Dauer eines kritischen API-Aufrufs und der anschließenden Datenverarbeitung eignet.
// In Ihrem Anwendungscode: performance.mark('start-data-processing'); // ... einige komplexe Datenverarbeitung ... performance.mark('end-data-processing'); performance.measure('data-processing-duration', 'start-data-processing', 'end-data-processing'); // In Ihrem Überwachungsskript: const customObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntriesByName('data-processing-duration')) { console.log(`Benutzerdefinierte Messung '${entry.name}': ${entry.duration.toFixed(2)}ms`); } }); customObserver.observe({ entryTypes: ['measure'] });
Erweiterte Konzepte und Best Practices
Um die Performance Observer API effektiv in einer professionellen Produktionsumgebung zu nutzen, sollten Sie diese Best Practices berücksichtigen.
- Berücksichtigen Sie immer `buffered: true`: Für Eintragstypen, die frühzeitig im Seitenladen auftreten können (z. B. „resource“, „paint“ oder „largest-contentful-paint“), ist die Verwendung des Puffermarkierungs-Flags unerlässlich, um zu vermeiden, dass diese verpasst werden.
- Überprüfen Sie die Browser-Unterstützung: Obwohl sie in modernen Browsern weitgehend unterstützt wird, ist es immer ratsam, vor der Verwendung die Existenz zu überprüfen. Sie können auch überprüfen, welche Eintragstypen von einem bestimmten Browser unterstützt werden.
- if ('PerformanceObserver' in window && PerformanceObserver.supportedEntryTypes.includes('longtask')) { // Sichere Verwendung von PerformanceObserver für lange Aufgaben }
- Senden Sie Daten an einen Analysedienst: Das Protokollieren von Daten in der Konsole ist großartig für die Entwicklung, aber für die reale Überwachung müssen Sie diese Daten aggregieren. Der beste Weg, diese Telemetrie vom Client zu senden, ist die navigator.sendBeacon() API. Es ist ein nicht blockierender Mechanismus, der für das Senden kleiner Datenmengen an einen Server konzipiert ist, und er funktioniert zuverlässig, selbst wenn eine Seite entladen wird.
- Gruppieren Sie Observer nach Anliegen: Sie können zwar einen einzelnen Observer für mehrere Eintragstypen verwenden, aber es ist oft sauberer, separate Observer für verschiedene Anliegen zu erstellen (z. B. einen für Core Web Vitals, einen für Ressourcen-Timings, einen für benutzerdefinierte Metriken). Dies verbessert die Lesbarkeit und Wartbarkeit des Codes.
- Verstehen Sie den Performance-Overhead: Die API ist so konzipiert, dass sie einen sehr geringen Overhead hat. Eine sehr komplexe Callback-Funktion, die aufwändige Berechnungen durchführt, könnte jedoch potenziell die Performance beeinträchtigen. Halten Sie Ihre Observer-Callbacks schlank und effizient. Verschieben Sie alle aufwändigen Verarbeitungen an einen Web Worker oder senden Sie die Rohdaten zur Verarbeitung dorthin.
Fazit: Aufbau einer Performance-First-Kultur
Die Performance Observer API ist mehr als nur ein weiteres Tool; sie ist eine grundlegende Veränderung in unserer Herangehensweise an die Web-Performance. Sie bringt uns von reaktiven, einmaligen Messungen zu einer proaktiven, kontinuierlichen Überwachung, die die wahre, dynamische Erfahrung unserer Benutzer auf der ganzen Welt widerspiegelt. Durch die Bereitstellung einer zuverlässigen und effizienten Möglichkeit, Core Web Vitals, lange Aufgaben, Ressourcen-Timings und benutzerdefinierte Metriken zu erfassen, befähigt sie Entwickler, Performance-Engpässe zu identifizieren und zu beheben, bevor sie sich auf eine erhebliche Anzahl von Benutzern auswirken.
Die Einführung der Performance Observer API ist ein entscheidender Schritt zum Aufbau einer Performance-First-Kultur in jedem Entwicklungsteam. Wenn Sie messen können, was wichtig ist, können Sie verbessern, was wichtig ist. Beginnen Sie noch heute mit der Integration dieser Observer in Ihre Projekte. Ihre Benutzer – wo auch immer sie sich auf der Welt befinden – werden Ihnen für die schnellere, reibungslosere und angenehmere Erfahrung danken.