Signatur
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
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 });
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 });
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).
presentationTimekam erst nach der ursprünglichen API dazu. Prüfe vorher perPerformanceObserver.supportedEntryTypesund optionalem Zugriff (?.), ob die API verfügbar ist. - Kann fehlen: Der Präsentationszeitpunkt hängt vom Browser ab. Der Wert kann
nulloder0sein, 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.