Start · Sprachen · JavaScript · Referenz · PerformanceEventTiming

PerformanceEventTiming

Schnittstelle

Liefert als Teil der Event Timing API Zeitmessungen zu Ereignissen aus Benutzerinteraktionen (Klick, Taste, Pointer), etwa Eingabeverzögerung, Verarbeitungszeit und Gesamtdauer bis zum nächsten Frame.

seit JavaScript Chrome/Edge 76+, Firefox 89+; Safari erst in neuer Kategorie: webapi

Signatur

interface PerformanceEventTiming extends PerformanceEntry

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 vom startTime bis 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 oder null, 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

Typ
PerformanceEventTiming
Beschreibung
Einträge kommen über 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 });
click auf <button id="kaufen"> { dauer: 184, eingabeverzoegerung: 12, verarbeitung: 150, darstellung: 22 }

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 });
Erste Eingabe: pointerdown, Verzögerung 3.4 ms

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}`);
Klicks: 7, Tastendrücke: 23