Signatur
Beschreibung
PerformanceEventTiming beschreibt, wie schnell eine Seite auf Benutzereingaben reagiert. Für jedes Ereignis wird gemessen, wann der Benutzer es ausgelöst hat (startTime), wann der erste Event-Handler lief (processingStart), wann der letzte fertig war (processingEnd) und wann danach der nächste Frame gezeichnet wurde (über duration). Das ist die Datengrundlage für Web-Vitals-Kennzahlen wie Interaction to Next Paint (INP) und das inzwischen abgelöste First Input Delay (FID).
Einträge bekommt man nicht über einen Konstruktor, sondern über einen PerformanceObserver mit dem Typ "event" (langsame Ereignisse, standardmäßig ab 104 ms) oder "first-input" (die erste Interaktion der Seite, egal wie schnell sie war). Mit der Option durationThreshold lässt sich die Schwelle senken, minimal auf 16 ms.
Wichtige Eigenschaften zusätzlich zu denen von PerformanceEntry:
name: Ereignistyp, z. B."click","keydown","pointerdown".entryType:"event"oder"first-input".startTime: Zeitstempel des Ereignisses (event.timeStamp).processingStart/processingEnd: Beginn und Ende der Handler-Ausführung.duration: Zeit vomstartTimebis zum nächsten gezeichneten Frame, auf 8 ms gerundet.interactionId: gruppiert zusammengehörige Ereignisse einer Interaktion (z. B.pointerdown,pointerup,click);0, wenn das Ereignis zu keiner Interaktion gehört.cancelable: ob das Ereignis abbrechbar ist.target: das zuletzt zugehörige DOM-Element odernull, wenn es nicht mehr im Dokument hängt.toJSON(): gibt eine JSON-Darstellung des Eintrags zurück.
Aus diesen Werten lassen sich drei Phasen ableiten: Eingabeverzögerung (processingStart - startTime), Verarbeitungszeit (processingEnd - processingStart) und Darstellungsverzögerung (startTime + duration - processingEnd). So erkennt man, ob der Hauptthread blockiert war, ob ein Handler zu lange lief oder ob das Rendern danach zu teuer war.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options.type Pflicht | "event" | "first-input" | Einstellung für PerformanceObserver.observe(): welche Art von PerformanceEventTiming-Einträgen beobachtet werden soll. |
|
| $options.durationThreshold | number | 104 | Nur bei type: "event": Mindestdauer in ms, ab der ein Eintrag erzeugt wird. Werte unter 16 werden auf 16 angehoben. |
| $options.buffered | boolean | false | Wenn true, werden auch Einträge geliefert, die schon vor der Registrierung des Beobachters gepuffert wurden (wichtig für "first-input"). |
Rückgabewert
PerformanceObserverEntryList.getEntries() im Callback eines PerformanceObserver an. Einen öffentlichen Konstruktor gibt es nicht.Beispiele
Langsame Interaktionen beobachten und in Phasen zerlegen
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const inputDelay = entry.processingStart - entry.startTime;
const processing = entry.processingEnd - entry.processingStart;
const presentation = entry.startTime + entry.duration - entry.processingEnd;
console.log(`${entry.name} auf`, entry.target, {
dauer: entry.duration,
eingabeverzoegerung: Math.round(inputDelay),
verarbeitung: Math.round(processing),
darstellung: Math.round(presentation),
});
}
});
// Alle Ereignisse ab 40 ms melden, auch bereits gepufferte
observer.observe({ type: 'event', durationThreshold: 40, buffered: true });
Erste Eingabe (First Input) erfassen
new PerformanceObserver((list) => {
const [firstInput] = list.getEntries();
const delay = firstInput.processingStart - firstInput.startTime;
console.log(`Erste Eingabe: ${firstInput.name}, Verzögerung ${delay.toFixed(1)} ms`);
}).observe({ type: 'first-input', buffered: true });
INP näherungsweise berechnen und an Analytics senden
if (PerformanceObserver.supportedEntryTypes?.includes('event')) {
const interactions = new Map(); // interactionId -> längste Dauer
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.interactionId) continue; // kein Teil einer Interaktion
const prev = interactions.get(entry.interactionId) ?? 0;
interactions.set(entry.interactionId, Math.max(prev, entry.duration));
}
}).observe({ type: 'event', durationThreshold: 16, buffered: true });
document.addEventListener('visibilitychange', () => {
if (document.visibilityState !== 'hidden') return;
const durations = [...interactions.values()].sort((a, b) => b - a);
// vereinfacht: pro 50 Interaktionen einen Ausreißer ignorieren
const index = Math.min(durations.length - 1, Math.floor(durations.length / 50));
const inp = durations[index] ?? 0;
navigator.sendBeacon('/analytics', JSON.stringify({ inp }));
});
}
Anzahl aller Ereignisse über performance.eventCounts
// Zählt alle Ereignisse, auch solche unter der Schwelle
const clicks = performance.eventCounts.get('click') ?? 0;
const keys = performance.eventCounts.get('keydown') ?? 0;
console.log(`Klicks: ${clicks}, Tastendrücke: ${keys}`);