Signatur
Beschreibung
PerformanceLongAnimationFrameTiming ist Teil der Long Animation Frames API (LoAF) und ersetzt in der Praxis die ältere Long Tasks API. Statt einzelner langer Tasks misst sie ganze Animationsframes: den Zeitraum vom Start der ersten Task bis zum Zeichnen des Frames, inklusive Rendering-Arbeit wie requestAnimationFrame-Callbacks, Stilberechnung und Layout. Ein Eintrag wird erzeugt, wenn ein Frame länger als 50 ms dauert.
Instanzen erzeugt man nicht selbst. Man erhält sie über einen PerformanceObserver mit dem Eintragstyp "long-animation-frame". Wichtige Eigenschaften neben den geerbten startTime, duration, name und entryType:
blockingDuration: Zeit in Millisekunden, in der der Hauptthread blockiert war (Summe der Anteile langer Tasks über 50 ms plus Renderzeit).renderStart: Beginn des Rendering-Zyklus (inklusiverequestAnimationFrame-Callbacks undResizeObserver).styleAndLayoutStart: Beginn der Stil- und Layoutberechnung.firstUIEventTimestamp: Zeitpunkt des ersten UI-Ereignisses (z. B. Klick oder Tastendruck), das in diesem Frame verarbeitet wurde.scripts: Array vonPerformanceScriptTiming-Objekten mit Zuordnung zu Skripten (Quell-URL, Funktionsname, Aufrufer, erzwungenes Layout u. a.).toJSON(): gibt eine JSON-Darstellung des Eintrags zurück.
Typische Anwendungsfälle sind Real User Monitoring (RUM) und die Diagnose schlechter Interaction to Next Paint (INP)-Werte: Über scripts lässt sich genau erkennen, welches Skript bzw. welche Funktion einen Frame ausgebremst hat, etwa ein Drittanbieter-Tag oder ein aufwendiger Event-Handler.
Rückgabewert
PerformanceObserver bzw. performance.getEntriesByType() geliefert. entryType und name haben beide den Wert "long-animation-frame".Beispiele
Lange Animationsframes beobachten
// Feature-Erkennung vor der Nutzung
if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(
`LoAF: ${entry.duration.toFixed(0)} ms, ` +
`blockiert: ${entry.blockingDuration.toFixed(0)} ms`
);
}
});
// buffered: true liefert auch Einträge vor der Registrierung
observer.observe({ type: 'long-animation-frame', buffered: true });
}
Verursachende Skripte ermitteln
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
for (const script of entry.scripts) {
console.log({
quelle: script.sourceURL,
funktion: script.sourceFunctionName,
aufrufer: script.invoker,
dauer: Math.round(script.duration),
erzwungenesLayout: Math.round(script.forcedStyleAndLayoutDuration)
});
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
Phasen eines Frames aufschlüsseln
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const ende = entry.startTime + entry.duration;
const skriptZeit = entry.renderStart - entry.startTime;
const renderZeit = ende - entry.renderStart;
const layoutZeit = ende - entry.styleAndLayoutStart;
console.log(`Skripte: ${skriptZeit.toFixed(0)} ms, ` +
`Rendering: ${renderZeit.toFixed(0)} ms, ` +
`davon Stil/Layout: ${layoutZeit.toFixed(0)} ms`);
}
});
observer.observe({ type: 'long-animation-frame' });
LoAF-Daten an Monitoring senden
const observer = new PerformanceObserver((list) => {
const payload = list.getEntries()
.filter((e) => e.blockingDuration > 100)
.map((e) => e.toJSON());
if (payload.length > 0) {
navigator.sendBeacon('/rum/loaf', JSON.stringify(payload));
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
// Wichtig · Fallstricke
- Browser-Kompatibilität: Nur in Chromium-Browsern (Chrome/Edge ab Version 123) verfügbar; Firefox und Safari unterstützen die API nicht. Immer per
PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')prüfen. - Nicht über
performance.getEntries()ohne Weiteres zuverlässig abrufbar – verwenden Sie einenPerformanceObserver. Der interne Puffer fürbuffered: trueist begrenzt (ca. 200 Einträge). - Die Zuordnung in
scriptsgilt nur für Skripte, deren Einzeldauer über 5 ms liegt. Bei Skripten aus anderen Ursprüngen ohne passende CORS-Freigabe (crossorigin-Attribut) fehlen Angaben wiesourceFunctionNameteilweise. - Nur Arbeit im Hauptthread des eigenen Fensters (und gleichursprünglicher Frames) wird erfasst, Web Worker nicht.
durationundblockingDurationunterscheiden sich: Ein Frame kann lang sein, ohne stark zu blockieren. Für die Bewertung der Reaktionsfähigkeit istblockingDurationmeist aussagekräftiger.- Beim Senden an Monitoring-Dienste auf Datenmenge achten und URLs gegebenenfalls kürzen oder anonymisieren (Datenschutz).