Start · Sprachen · JavaScript · Referenz · PerformanceLongAnimationFrameTiming.paintTime

PerformanceLongAnimationFrameTiming.paintTime

Eigenschaft

Liefert als <code>DOMHighResTimeStamp</code> den Zeitpunkt, an dem die Rendering-Phase eines langen Animationsframes endete und der Browser mit dem Zeichnen (Paint) begann.

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

Signatur

PerformanceLongAnimationFrameTiming.paintTime

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:

  • renderStart bis styleAndLayoutStart: requestAnimationFrame-Callbacks und ResizeObserver-Callbacks
  • styleAndLayoutStart bis paintTime: Stilberechnung und Layout
  • paintTime bis presentationTime: 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

Typ
DOMHighResTimeStamp
Beschreibung
Zeitstempel in Millisekunden (relativ zu 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-Start: 1532.4 | Paint-Beginn: 1648.9

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 });
{ skripte: 92, styleUndLayout: 24, paintBisAnzeige: 6, gesamt: 128 }

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 });
}
Layout endete nach 116 ms

// Wichtig · Fallstricke

  • Browser-Unterstützung: Die Long Animation Frames API gibt es nur in Chromium-basierten Browsern (Chrome, Edge, Opera). paintTime kam erst später als die übrigen LoAF-Eigenschaften hinzu. Prüfen Sie deshalb mit PerformanceObserver.supportedEntryTypes und '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.
  • paintTime ist nicht der Zeitpunkt, an dem die Pixel tatsächlich auf dem Bildschirm erscheinen. Dafür gibt es presentationTime, das je nach Implementierung auch null sein 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.