Signatur
Beschreibung
Die Eigenschaft paintTime eines InteractionContentfulPaint-Eintrags gibt an, wann der Browser das Rendering (Style, Layout, Aufbau des Paint-Baums) für den Frame abgeschlossen und die Paint-Phase gestartet hat. In diesem Frame wurde erstmals der größte Inhalt angezeigt, der durch eine Interaktion (z. B. einen Klick, der eine Soft-Navigation in einer Single-Page-App auslöst) entstanden ist. Der Wert ist ein DOMHighResTimeStamp in Millisekunden relativ zu performance.timeOrigin.
Die Eigenschaft stammt aus dem PaintTimingMixin, das auch PerformancePaintTiming und LargestContentfulPaint verwenden. Ihr Gegenstück ist presentationTime, also der Zeitpunkt, an dem die Pixel tatsächlich auf dem Bildschirm erscheinen. Die Differenz presentationTime - paintTime zeigt, wie viel Zeit für Rasterung, Compositing und Anzeige nötig war. Der Abstand zwischen dem Interaktionszeitpunkt und paintTime umfasst dagegen die Arbeit auf dem Hauptthread (JavaScript, Style, Layout).
Einsetzen lässt sich paintTime vor allem beim Real User Monitoring von SPAs. Dort beschreibt das klassische LCP nur den ersten Seitenaufbau. Mit InteractionContentfulPaint misst man auch Ansichtswechsel, die per Client-Routing entstehen. Die Einträge fragt man über einen PerformanceObserver ab.
Rückgabewert
performance.timeOrigin. Er gibt an, wann die Rendering-Phase des betreffenden Frames endete und die Paint-Phase begann.Beispiele
paintTime von Interaction-Contentful-Paint-Einträgen beobachten
// Nur in Browsern mit Unterstützung für Soft Navigations / ICP
const supported = PerformanceObserver.supportedEntryTypes
.includes('interaction-contentful-paint');
if (supported) {
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Paint-Phase begann bei:', entry.paintTime.toFixed(1), 'ms');
}
});
observer.observe({ type: 'interaction-contentful-paint', buffered: true });
} else {
console.log('interaction-contentful-paint wird nicht unterstützt');
}
Rendering- und Präsentationsdauer aufschlüsseln
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const { paintTime, presentationTime } = entry;
// presentationTime kann fehlen oder 0 sein
if (presentationTime) {
const presentationDelay = presentationTime - paintTime;
console.log(`Paint → Anzeige: ${presentationDelay.toFixed(1)} ms`);
} else {
console.log(`Nur paintTime verfügbar: ${paintTime.toFixed(1)} ms`);
}
}
});
observer.observe({ type: 'interaction-contentful-paint', buffered: true });
Messwerte an ein RUM-Backend senden
const report = (data) => {
navigator.sendBeacon('/rum', JSON.stringify(data));
};
new PerformanceObserver((list) => {
const entries = list.getEntries();
const last = entries[entries.length - 1]; // größter bisheriger Kandidat
report({
metric: 'icp',
paintTime: Math.round(last.paintTime),
startTime: Math.round(last.startTime),
url: location.pathname
});
}).observe({ type: 'interaction-contentful-paint', buffered: true });
// Wichtig · Fallstricke
- Experimentell:
InteractionContentfulPaintgibt es bisher nur in Chromium-basierten Browsern. Je nach Version muss die Funktion per Origin Trial oder Flag (Soft Navigations) freigeschaltet werden. Firefox und Safari unterstützen sie nicht. Prüfe die Unterstützung immer vorher überPerformanceObserver.supportedEntryTypes. - Der Name und das Verhalten der API können sich noch ändern. In Produktivcode sollte man darauf nicht fest aufbauen.
paintTimeist nicht der Zeitpunkt, an dem der Nutzer etwas sieht. Dafür stehtpresentationTime. Das kann aber in manchen Implementierungen fehlen oder0sein.- Aus Datenschutzgründen (Schutz vor Timing-Angriffen) können die Zeitstempel gröber gerundet sein, besonders ohne Cross-Origin-Isolation.
- Pro Interaktion können mehrere Einträge entstehen, weil immer größere Inhaltskandidaten gemeldet werden. Aussagekräftig ist in der Regel der letzte Eintrag vor der nächsten Interaktion.