Start · Sprachen · JavaScript · Referenz · PerformanceLongAnimationFrameTiming.presentationTime

PerformanceLongAnimationFrameTiming.presentationTime

Eigenschaft

Schreibgeschützter Zeitstempel (<code>DOMHighResTimeStamp</code>), zu dem das Ergebnis eines langen Animation-Frames tatsächlich auf dem Bildschirm angezeigt wurde.

seit JavaScript Experimentell: nur Chromium-basierte Browser (Long Kategorie: webapi

Signatur

PerformanceLongAnimationFrameTiming.presentationTime

Beschreibung

Die Eigenschaft presentationTime gehört zu den Paint-Timing-Angaben eines PerformanceLongAnimationFrameTiming-Eintrags (Long Animation Frames API, kurz LoAF). Sie gibt an, wann das Update der Benutzeroberfläche, das in diesem langen Frame berechnet wurde, tatsächlich auf dem Display sichtbar wurde. Der Wert ist ein DOMHighResTimeStamp in Millisekunden relativ zu performance.timeOrigin.

Während startTime und duration nur die Arbeit im Main-Thread beschreiben und paintTime das Ende der Rendering-Phase markiert, umfasst presentationTime auch die Zeit, die Compositor, GPU und Display bis zur Anzeige brauchen. Damit misst du die Verzögerung, die Nutzer wirklich wahrnehmen. Das ist z. B. hilfreich, wenn du INP-Probleme (Interaction to Next Paint) genauer untersuchst.

Typischerweise liest du den Wert in einem PerformanceObserver mit dem Eintragstyp "long-animation-frame" aus. Die Differenz presentationTime - paintTime zeigt dir die Verzögerung nach dem Main-Thread, die Differenz presentationTime - startTime die gesamte wahrgenommene Frame-Dauer.

Rückgabewert

Typ
DOMHighResTimeStamp | null
Beschreibung
Zeitstempel in Millisekunden (relativ zu performance.timeOrigin), zu dem der Frame angezeigt wurde. Wenn der Browser den Präsentationszeitpunkt nicht ermitteln kann oder aus Datenschutzgründen nicht offenlegt, kann der Wert null oder 0 sein.

Beispiele

Präsentationszeit langer Frames beobachten

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log({
      start: entry.startTime.toFixed(1),
      dauer: entry.duration.toFixed(1),
      angezeigt: entry.presentationTime?.toFixed(1) ?? 'nicht verfügbar'
    });
  }
});

// buffered: true liefert auch Einträge von vor der Registrierung
observer.observe({ type: 'long-animation-frame', buffered: true });
{ start: '1523.4', dauer: '87.2', angezeigt: '1622.9' }

Verzögerung nach dem Main-Thread berechnen

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    const { startTime, paintTime, presentationTime } = entry;
    if (!presentationTime || !paintTime) continue; // nicht unterstützt

    const nachPaint = presentationTime - paintTime;
    const gesamt = presentationTime - startTime;
    console.log(`Compositor/GPU: ${nachPaint.toFixed(1)} ms, gesamt: ${gesamt.toFixed(1)} ms`);
  }
}).observe({ type: 'long-animation-frame', buffered: true });
Compositor/GPU: 12.4 ms, gesamt: 99.5 ms

Feature-Erkennung und Fallback für Analytics

const supportsLoAF = PerformanceObserver.supportedEntryTypes?.includes('long-animation-frame');

if (supportsLoAF) {
  new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Fallback: Ende des Main-Thread-Anteils, falls presentationTime fehlt
      const sichtbarAb = entry.presentationTime || entry.startTime + entry.duration;
      navigator.sendBeacon('/rum', JSON.stringify({
        typ: 'loaf',
        start: Math.round(entry.startTime),
        sichtbarAb: Math.round(sichtbarAb),
        blockiert: Math.round(entry.blockingDuration)
      }));
    }
  }).observe({ type: 'long-animation-frame', buffered: true });
} else {
  console.log('Long Animation Frames API wird nicht unterstützt');
}

// Wichtig · Fallstricke

  • Kompatibilität: Die Long Animation Frames API ist experimentell und gibt es nur in Chromium-Browsern (Chrome, Edge, Opera). presentationTime kam erst nach der ursprünglichen API dazu. Prüfe vorher per PerformanceObserver.supportedEntryTypes und optionalem Zugriff (?.), ob die API verfügbar ist.
  • Kann fehlen: Der Präsentationszeitpunkt hängt vom Browser ab. Der Wert kann null oder 0 sein, z. B. wenn der Frame nie angezeigt wurde (Tab im Hintergrund) oder der Browser ihn nicht offenlegt. Plane dafür immer einen Fallback ein.
  • Grobe Auflösung: Um Timing-Angriffe zu erschweren, kann der Wert gerundet sein, vor allem ohne Cross-Origin-Isolation. Einzelwerte sind deshalb nicht exakt. Verlässliche Aussagen bekommst du erst über viele Messungen hinweg.
  • Nur Frames ab 50 ms Dauer erzeugen einen Eintrag. Kurze Frames bekommst du über diese API nicht zu sehen.
  • Die Eigenschaft ist schreibgeschützt. Zuweisungen werden ignoriert.