Signatur
Beschreibung
Mit observe() meldest du einen PerformanceObserver für einen oder mehrere Performance-Eintragstypen an. Sobald der Browser passende Einträge erzeugt, zum Beispiel für geladene Ressourcen, eigene Marker, lange Tasks oder Web-Vitals-Messwerte, ruft er den im Konstruktor übergebenen Callback mit einer PerformanceObserverEntryList auf.
Es gibt zwei Aufrufformen, die sich gegenseitig ausschließen:
entryTypes: Ein Array mehrerer Typen auf einmal. Jeder weitere Aufruf ersetzt die bisherige Liste. Zusätzliche Optionen wiebufferedoderdurationThresholdsind in dieser Form nicht erlaubt.type: Genau ein Typ pro Aufruf. Hier sindbufferedund (beievent)durationThresholderlaubt. Mehrere Aufrufe mit unterschiedlichen Typen ergänzen sich. Rufst du denselben Typ erneut auf, werden nur dessen Optionen aktualisiert.
Die type-Form mit buffered: true ist heute die empfohlene Variante. Damit bekommst du auch Einträge, die schon vor dem Anmelden des Observers entstanden sind. Das ist wichtig für Messwerte wie LCP oder FCP, weil die Messskripte oft erst spät geladen werden. Welche Typen der Browser unterstützt, verrät PerformanceObserver.supportedEntryTypes.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options Pflicht | PerformanceObserverInit | Konfigurationsobjekt. Es muss entweder entryTypes oder type enthalten, aber nicht beides. |
|
| $options.entryTypes | string[] | Liste der zu beobachtenden Eintragstypen, z. B. ['mark', 'measure', 'resource']. Nicht unterstützte Typen werden ignoriert (mit einer Warnung in der Konsole). |
|
| $options.type | string | Ein einzelner Eintragstyp, z. B. 'largest-contentful-paint', 'longtask', 'event' oder 'layout-shift'. |
|
| $options.buffered | boolean | false | Nur zusammen mit type nutzbar. Bei true werden auch bereits gepufferte Einträge geliefert, die vor dem Aufruf entstanden sind. |
| $options.durationThreshold | number | 104 | Nur für type: 'event': Mindestdauer in Millisekunden, ab der Event-Timing-Einträge gemeldet werden. Der kleinste erlaubte Wert ist 16. |
Beispiele
Largest Contentful Paint inklusive gepufferter Einträge messen
const lcpObserver = new PerformanceObserver((list) => {
const entries = list.getEntries();
const last = entries.at(-1); // der jeweils aktuellste LCP-Kandidat
console.log('LCP:', Math.round(last.startTime), 'ms', last.element);
});
lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });
Mehrere Typen per entryTypes beobachten (eigene Marker und Messungen)
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.entryType}: ${entry.name} – ${entry.duration.toFixed(1)} ms`);
}
});
observer.observe({ entryTypes: ['mark', 'measure'] });
performance.mark('daten-start');
await fetch('/api/daten');
performance.mark('daten-ende');
performance.measure('daten-laden', 'daten-start', 'daten-ende');
Typen einzeln hinzufügen, mit Feature-Erkennung
const wanted = ['longtask', 'layout-shift', 'event'];
const supported = PerformanceObserver.supportedEntryTypes;
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((e) => console.log(e.entryType, Math.round(e.duration ?? 0)));
});
for (const type of wanted.filter((t) => supported.includes(t))) {
// Die type-Form ergänzt: jeder Aufruf fügt einen weiteren Typ hinzu
const opts = { type, buffered: true };
if (type === 'event') opts.durationThreshold = 40;
observer.observe(opts);
}
// Später beenden und nicht zugestellte Einträge abholen
window.addEventListener('pagehide', () => {
const rest = observer.takeRecords();
observer.disconnect();
console.log('Nicht zugestellt:', rest.length);
});
// Wichtig · Fallstricke
- Nicht mischen: Wenn du
entryTypesundtypein einem Aufruf angibst oder keines von beiden, wirft der Browser einenTypeError. Wechselst du bei einem bestehenden Observer von einer Form zur anderen, wirft er einenInvalidModificationError(DOMException). entryTypesersetzt: Ein zweiter Aufruf mitentryTypesüberschreibt die vorherige Liste. Mittypeergänzen sich die Aufrufe dagegen.bufferedignoriert: In Kombination mitentryTypeshatbufferedkeine Wirkung. Verwende dietype-Form.- Unbekannte Typen lösen keinen Fehler aus, sie werden still ignoriert (höchstens mit einer Konsolenwarnung). Prüfe deshalb vorher
PerformanceObserver.supportedEntryTypes. Typen wielongtask,layout-shift,largest-contentful-paintoderlong-animation-framegibt es teilweise nur in Chromium-Browsern. - Der Callback läuft asynchron und gebündelt, nicht sofort pro Eintrag. Vor dem
disconnect()kannst du mittakeRecords()Einträge abholen, die noch nicht zugestellt wurden. - Der Pufferspeicher ist je nach Typ begrenzt. Bei
resourcegiltperformance.setResourceTimingBufferSize(), standardmäßig 250 Einträge. - Die Methode funktioniert auch in Web Workern und in Node.js (
perf_hooks). Dort stehen jeweils andere Eintragstypen zur Verfügung.