Signatur
Beschreibung
Mit PerformanceObserver reagierst du ereignisgesteuert auf neue Leistungsmessungen, statt die Zeitleiste regelmäßig über performance.getEntries() abzufragen. Der Browser sammelt Einträge wie Ressourcen-Ladezeiten, Navigations-Timings, eigene Marken (mark/measure), Paint-Zeitpunkte, Long Tasks oder Layout-Verschiebungen und übergibt sie gebündelt an deinen Callback.
Typische Einsatzgebiete sind Real User Monitoring (RUM) und die Erfassung der Core Web Vitals (LCP, CLS, INP) direkt im Browser der Nutzer. Der Observer verursacht kaum Overhead, da die Callbacks asynchron und mit niedriger Priorität ausgeführt werden und die Hauptthread-Arbeit nicht blockieren.
Die Schnittstelle besteht aus dem Konstruktor new PerformanceObserver(callback), den Instanzmethoden observe(), disconnect() und takeRecords() sowie der statischen Eigenschaft PerformanceObserver.supportedEntryTypes, mit der du vorab prüfen kannst, welche Eintragstypen der Browser unterstützt.
Mit der Option buffered: true erhältst du auch Einträge, die bereits vor dem Anlegen des Observers entstanden sind – wichtig, weil Analyse-Skripte oft erst spät geladen werden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $callback Pflicht | (list: PerformanceObserverEntryList, observer: PerformanceObserver, options?: { droppedEntriesCount: number }) => void | Konstruktor-Argument. Wird aufgerufen, wenn neue Einträge der beobachteten Typen vorliegen. list.getEntries(), getEntriesByType() und getEntriesByName() liefern die Einträge. |
|
| $options.type | string | Für observe(): ein einzelner Eintragstyp, z. B. 'largest-contentful-paint'. Nur mit type sind buffered und durationThreshold nutzbar. |
|
| $options.entryTypes | string[] | Für observe(): mehrere Eintragstypen auf einmal. Darf nicht mit type kombiniert werden. |
|
| $options.buffered | boolean | false | Liefert zusätzlich bereits gepufferte, ältere Einträge des Typs. |
| $options.durationThreshold | number | 104 | Nur für type: 'event': Mindestdauer in Millisekunden (min. 16), ab der Event-Timing-Einträge gemeldet werden. |
Rückgabewert
observe() und disconnect() geben undefined zurück, takeRecords() ein Array von PerformanceEntry-Objekten.Beispiele
Ressourcen-Ladezeiten protokollieren
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.name}: ${entry.duration.toFixed(1)} ms`);
}
});
// Auch bereits geladene Ressourcen berücksichtigen
observer.observe({ type: 'resource', buffered: true });
Largest Contentful Paint (LCP) messen
if (PerformanceObserver.supportedEntryTypes.includes('largest-contentful-paint')) {
let lcp = 0;
const po = new PerformanceObserver((list) => {
const entries = list.getEntries();
lcp = entries.at(-1).startTime; // letzter Kandidat zählt
});
po.observe({ type: 'largest-contentful-paint', buffered: true });
// Beim Verlassen der Seite Ergebnis senden
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
po.takeRecords();
po.disconnect();
navigator.sendBeacon('/rum', JSON.stringify({ lcp }));
}
}, { once: true });
}
Eigene Messungen mit mark/measure beobachten
const po = new PerformanceObserver((list, observer) => {
list.getEntriesByType('measure').forEach((m) => {
console.log(`${m.name} dauerte ${Math.round(m.duration)} ms`);
});
observer.disconnect(); // nach erster Meldung beenden
});
po.observe({ entryTypes: ['measure'] });
const loadUsers = async () => {
performance.mark('users-start');
await fetch('https://jsonplaceholder.typicode.com/users');
performance.mark('users-end');
performance.measure('users-laden', 'users-start', 'users-end');
};
loadUsers();
Long Tasks erkennen
const longTasks = new PerformanceObserver((list) => {
for (const task of list.getEntries()) {
console.warn(`Long Task: ${task.duration} ms ab ${Math.round(task.startTime)} ms`);
}
});
longTasks.observe({ type: 'longtask', buffered: true });
// Wichtig · Fallstricke
typeundentryTypesnicht mischen: Beides in einemobserve()-Aufruf wirft einenTypeError.bufferedwirkt nur zusammen mittype.- Unterstützung variiert je Eintragstyp:
longtask,largest-contentful-paint,layout-shiftundeventsind vor allem in Chromium-Browsern verfügbar; Safari und Firefox unterstützen nur einen Teil. Immer mitPerformanceObserver.supportedEntryTypesprüfen – unbekannte Typen werden stillschweigend ignoriert (Konsolenwarnung). - Asynchrone Zustellung: Der Callback läuft verzögert (Idle-Priorität). Vor dem Verlassen der Seite mit
takeRecords()noch ausstehende Einträge abholen. - Puffergrenzen: Der Ressourcen-Puffer fasst standardmäßig 250 Einträge (
performance.setResourceTimingBufferSize()); verworfene Einträge meldetdroppedEntriesCountim dritten Callback-Argument. - Datenschutz/CORS: Bei Cross-Origin-Ressourcen sind detaillierte Timings (z. B.
transferSize, DNS-Zeiten) nur mit dem Response-HeaderTiming-Allow-Originverfügbar, sonst 0. - Nicht mehr benötigte Observer mit
disconnect()beenden, um Speicher freizugeben.