Signatur
Beschreibung
Die schreibgeschützte Eigenschaft paintTime gehört zu Einträgen vom Typ "long-animation-frame" (Long Animation Frames API, kurz LoAF). Sie gibt an, wann der Browser die Rendering-Phase abgeschlossen hat, also Stilberechnung und Layout, und die Paint-Phase begonnen hat. Die Eigenschaft stammt aus dem PaintTimingMixin, das auch PerformancePaintTiming nutzt.
Der Wert ist ein hochauflösender Zeitstempel in Millisekunden relativ zu performance.timeOrigin. Zusammen mit startTime, renderStart, styleAndLayoutStart und presentationTime lässt sich ein langer Frame in einzelne Phasen zerlegen:
renderStartbisstyleAndLayoutStart:requestAnimationFrame-Callbacks undResizeObserver-CallbacksstyleAndLayoutStartbispaintTime: Stilberechnung und LayoutpaintTimebispresentationTime: Paint, Compositing und Anzeige auf dem Bildschirm
Das ist vor allem für die Analyse schlechter INP-Werte (Interaction to Next Paint) nützlich. So erkennen Sie, ob ein langsamer Frame durch Skripte, durch Layout-Arbeit oder erst durch das Zeichnen selbst entsteht.
Rückgabewert
performance.timeOrigin), an dem die Rendering-Phase endete und die Paint-Phase begann.Beispiele
Lange Frames beobachten und paintTime ausgeben
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Frame-Start:', entry.startTime.toFixed(1),
'| Paint-Beginn:', entry.paintTime?.toFixed(1));
}
});
// buffered: true liefert auch Einträge, die schon vor dem Registrieren entstanden sind
observer.observe({ type: 'long-animation-frame', buffered: true });
Frame in Phasen zerlegen (Skript, Layout, Paint)
const analyzeFrame = (entry) => {
const layoutStart = entry.styleAndLayoutStart || entry.renderStart;
return {
skripte: Math.round(layoutStart - entry.startTime),
styleUndLayout: Math.round(entry.paintTime - layoutStart),
// presentationTime kann null sein, falls nicht unterstützt
paintBisAnzeige: entry.presentationTime
? Math.round(entry.presentationTime - entry.paintTime)
: null,
gesamt: Math.round(entry.duration),
};
};
new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => console.table(analyzeFrame(entry)));
}).observe({ type: 'long-animation-frame', buffered: true });
Feature-Erkennung vor der Auswertung
const supportsLoAF = PerformanceObserver.supportedEntryTypes
.includes('long-animation-frame');
if (!supportsLoAF) {
console.log('Long Animation Frames API nicht verfügbar');
} else {
new PerformanceObserver((list) => {
const [entry] = list.getEntries();
if (entry && 'paintTime' in entry) {
console.log('Layout endete nach', Math.round(entry.paintTime - entry.startTime), 'ms');
} else {
console.log('paintTime wird in diesem Browser nicht unterstützt');
}
}).observe({ type: 'long-animation-frame', buffered: true });
}
// Wichtig · Fallstricke
- Browser-Unterstützung: Die Long Animation Frames API gibt es nur in Chromium-basierten Browsern (Chrome, Edge, Opera).
paintTimekam erst später als die übrigen LoAF-Eigenschaften hinzu. Prüfen Sie deshalb mitPerformanceObserver.supportedEntryTypesund'paintTime' in entry, ob die Funktion verfügbar ist. Firefox und Safari unterstützen die API derzeit nicht. - Einträge werden nur für Frames erzeugt, die länger als 50 ms dauern. Kurze Frames erscheinen nicht.
paintTimeist nicht der Zeitpunkt, an dem die Pixel tatsächlich auf dem Bildschirm erscheinen. Dafür gibt espresentationTime, das je nach Implementierung auchnullsein kann.- Die Zeitauflösung wird aus Sicherheitsgründen (Schutz vor Timing-Angriffen) möglicherweise gerundet. Ohne Cross-Origin-Isolierung ist die Auflösung gröber.
- Werten Sie die Daten gesammelt aus (z. B. per
navigator.sendBeacon()an Ihr RUM-Backend). Einzelwerte schwanken stark je nach Gerät und Last.