Start · Sprachen · JavaScript · Referenz · new PerformanceObserver()

new PerformanceObserver()

Methode

Erstellt ein neues <code>PerformanceObserver</code>-Objekt, das den übergebenen Callback aufruft, sobald neue Performance-Einträge der beobachteten Typen erfasst werden.

seit JavaScript Baseline: alle modernen Browser (seit 2017); Node. Kategorie: webapi

Signatur

new PerformanceObserver(callback)

Beschreibung

Der Konstruktor PerformanceObserver() erzeugt einen Beobachter für die Performance Timeline. Anders als beim Abfragen mit performance.getEntriesByType() muss man nicht regelmäßig nachsehen: Der Browser ruft den Callback asynchron auf, sobald neue Einträge wie resource, navigation, mark, measure, paint, largest-contentful-paint, layout-shift, longtask oder event vorliegen.

Direkt nach dem Erzeugen beobachtet das Objekt noch nichts. Erst ein Aufruf von observer.observe() legt fest, welche Eintragstypen gemeldet werden, entweder mit { type: '…', buffered: true } für einen einzelnen Typ oder mit { entryTypes: [...] } für mehrere.

Typische Einsatzgebiete sind Real User Monitoring (RUM), das Messen der Core Web Vitals (LCP, CLS, INP), das Erkennen langer Tasks, die den Haupt-Thread blockieren, und das Auswerten eigener Messpunkte, die mit performance.mark() und performance.measure() gesetzt wurden.

Parameter

Name Typ Default Beschreibung
$callback Pflicht (entries: PerformanceObserverEntryList, observer: PerformanceObserver, options?: { droppedEntriesCount: number }) => void Wird aufgerufen, sobald beobachtete Einträge erfasst werden. Das erste Argument ist eine PerformanceObserverEntryList (mit getEntries(), getEntriesByType() und getEntriesByName()), das zweite der Beobachter selbst. Das dritte Argument enthält droppedEntriesCount, also die Zahl der Einträge, die verloren gingen, weil der Puffer voll war (nur bei buffered: true).

Rückgabewert

Typ
PerformanceObserver
Beschreibung
Ein neues PerformanceObserver-Objekt, das erst nach einem Aufruf von observe() Einträge meldet.

Beispiele

Ressourcen-Ladezeiten protokollieren

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(`${entry.name}: ${entry.duration.toFixed(1)} ms`);
  }
});

// buffered: true liefert auch Einträge, die vor observe() entstanden sind
observer.observe({ type: 'resource', buffered: true });
https://example.com/app.js: 84.3 ms https://example.com/style.css: 41.7 ms

Largest Contentful Paint (LCP) messen

let lcp = 0;

const lcpObserver = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  // Der letzte Eintrag ist der aktuelle LCP-Kandidat
  lcp = entries.at(-1).startTime;
});

lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });

// Beim Verlassen der Seite den Wert senden
addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    lcpObserver.takeRecords();
    lcpObserver.disconnect();
    navigator.sendBeacon('/analytics', JSON.stringify({ lcp }));
  }
}, { once: true });

Eigene Messpunkte mit mark/measure auswerten

const observer = new PerformanceObserver((list, obs) => {
  for (const m of list.getEntriesByType('measure')) {
    console.log(`${m.name} dauerte ${m.duration.toFixed(2)} ms`);
  }
  obs.disconnect(); // nur einmal auswerten
});
observer.observe({ entryTypes: ['measure'] });

performance.mark('sort-start');
const data = Array.from({ length: 100_000 }, () => Math.random()).sort();
performance.mark('sort-end');
performance.measure('sortieren', 'sort-start', 'sort-end');
sortieren dauerte 57.12 ms

Lange Tasks erkennen (mit Feature-Prüfung)

const supported = PerformanceObserver.supportedEntryTypes ?? [];

if (supported.includes('longtask')) {
  new PerformanceObserver((list) => {
    for (const task of list.getEntries()) {
      console.warn(`Langer Task: ${Math.round(task.duration)} ms`);
    }
  }).observe({ type: 'longtask', buffered: true });
} else {
  console.info('longtask wird hier nicht unterstützt');
}
Langer Task: 132 ms

// Wichtig · Fallstricke

  • Ohne new geht es nicht: Ein Aufruf als normale Funktion wirft einen TypeError. Das gilt auch, wenn callback fehlt oder keine Funktion ist.
  • type und entryTypes nicht mischen: In observe() schließen sich beide Optionen gegenseitig aus. buffered und durationThreshold funktionieren nur zusammen mit type.
  • Die Unterstützung ist je nach Eintragstyp verschieden: longtask, largest-contentful-paint und layout-shift gibt es derzeit vor allem in Chromium-Browsern, Safari und Firefox unterstützen sie nur teilweise oder gar nicht. Vorher mit PerformanceObserver.supportedEntryTypes prüfen. Nicht unterstützte Typen werden stillschweigend ignoriert, meist nur mit einer Warnung in der Konsole.
  • Der Callback läuft asynchron (bei Leerlauf oder gebündelt). Deshalb vor dem Verlassen der Seite noch ausstehende Einträge mit takeRecords() abholen.
  • Performance: Im Callback keine aufwendigen Arbeiten und keine DOM-Änderungen durchführen, sonst verfälscht man die Messung selbst. Nicht mehr benötigte Beobachter mit disconnect() beenden.
  • Datenschutz: Bei Ressourcen von fremden Ursprüngen sind die meisten Zeitwerte 0, solange der Server keinen Timing-Allow-Origin-Header sendet. Zeitstempel sind außerdem absichtlich ungenauer gemacht (Schutz vor Spectre-Angriffen).
  • In Node.js steht die Klasse über require('node:perf_hooks') zur Verfügung, ab Version 16 auch global. Unterstützt werden dort andere Eintragstypen (z. B. gc, function, http).