Signatur
Beschreibung
PerformanceScriptTiming gehört zur Long Animation Frames API (LoAF). Ein langer Animationsframe liegt vor, wenn das Rendern eines Frames länger als 50 ms dauert. Jeder solche Frame wird als PerformanceLongAnimationFrameTiming-Eintrag gemeldet. Dessen Eigenschaft scripts enthält ein Array von PerformanceScriptTiming-Objekten: eines für jedes Skript, das mindestens 5 ms zur Laufzeit des Frames beigetragen hat.
Die Schnittstelle beantwortet die zentrale Frage beim Debuggen schlechter Interaction to Next Paint-Werte (INP): Welcher Code hat den Hauptthread blockiert? Du erfährst, welche Datei (sourceURL), welche Funktion (sourceFunctionName) und welcher Auslöser (invoker, z. B. BUTTON#buy.onclick) verantwortlich war, wie lange das Skript lief und wie viel Zeit davon auf erzwungenes, synchrones Style- und Layout-Neuberechnen (Layout Thrashing) entfiel.
Die Objekte erzeugst du nicht selbst, es gibt keinen Konstruktor. Du bekommst sie über einen PerformanceObserver mit dem Typ "long-animation-frame". Typische Einsatzgebiete sind Real-User-Monitoring (RUM), die Zuordnung von Leistungsproblemen zu Drittanbieter-Skripten und gezielte Optimierung in eigenen Event-Handlern.
Wichtige Eigenschaften (alle schreibgeschützt), zusätzlich zu den von PerformanceEntry geerbten:
entryType: immer"script".name: ebenfalls"script".startTime/duration: Beginn und Gesamtdauer des Skripts in Millisekunden. Die Dauer schließt anschließend abgearbeitete Microtasks ein.executionStart: Zeitpunkt, ab dem das Skript tatsächlich ausgeführt wurde, also nach dem Kompilieren.forcedStyleAndLayoutDuration: Zeit für erzwungene synchrone Style- und Layout-Berechnungen.pauseDuration: Zeit in synchron blockierenden Aufrufen wiealert()oder synchronem XHR.invoker/invokerType: Auslöser und dessen Typ ("classic-script","module-script","event-listener","user-callback","resolve-promise","reject-promise").sourceURL,sourceFunctionName,sourceCharPosition: Herkunft im Quellcode.window/windowAttribution: das zugehörige Fenster und seine Beziehung zum aktuellen Dokument ("self","descendant","ancestor","same-page","other").
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $invoker Pflicht | string | Beschreibt den Auslöser, z. B. "BUTTON#buy.onclick", "Window.setTimeout", "Response.json.then" oder die Skript-URL. (Eigenschaft, kein Funktionsparameter) |
|
| $invokerType Pflicht | "classic-script"|"module-script"|"event-listener"|"user-callback"|"resolve-promise"|"reject-promise" | Art des Einstiegspunkts, über den das Skript lief. | |
| $executionStart Pflicht | DOMHighResTimeStamp | Beginn der eigentlichen Ausführung nach dem Kompilieren. executionStart - startTime entspricht ungefähr der Parse- und Kompilierzeit. |
|
| $forcedStyleAndLayoutDuration Pflicht | DOMHighResTimeStamp | Summe der Zeit für erzwungene synchrone Style- und Layout-Berechnungen, etwa durch das Lesen von offsetHeight direkt nach DOM-Änderungen. |
|
| $pauseDuration Pflicht | DOMHighResTimeStamp | Zeit in synchron pausierenden Operationen, z. B. alert(), confirm() oder synchronem XMLHttpRequest. |
|
| $sourceURL Pflicht | string | URL des Skripts. Leerer String, wenn sie nicht ermittelbar ist. | |
| $sourceFunctionName Pflicht | string | Name der ausgeführten Funktion. Bei anonymen Funktionen leer. | |
| $sourceCharPosition Pflicht | number | Zeichenposition im Skript. -1, wenn unbekannt. |
|
| $window Pflicht | Window|null | Das Fenster, zu dem das Skript gehört. null bei Cross-Origin-Fenstern bzw. wenn es nicht zugänglich ist. |
|
| $windowAttribution Pflicht | "self"|"descendant"|"ancestor"|"same-page"|"other" | Beziehung des Skript-Fensters zum aktuellen Dokument, z. B. "descendant" für ein eingebettetes iframe. |
Rückgabewert
PerformanceLongAnimationFrameTiming.scripts. toJSON() liefert eine JSON-taugliche Darstellung aller Eigenschaften, allerdings ohne window.Beispiele
Skripte aus langen Animationsframes protokollieren
const observer = new PerformanceObserver((list) => {
for (const frame of list.getEntries()) {
for (const script of frame.scripts) {
console.log(
`${script.invokerType} | ${script.invoker} | ` +
`${Math.round(script.duration)} ms | ${script.sourceURL}`
);
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
Layout Thrashing und Kompilierzeit erkennen
new PerformanceObserver((list) => {
list.getEntries()
.flatMap((frame) => frame.scripts)
.filter((s) => s.forcedStyleAndLayoutDuration > 10)
.forEach((s) => {
const compile = s.executionStart - s.startTime;
console.warn('Erzwungenes Layout:', {
funktion: s.sourceFunctionName || '(anonym)',
quelle: `${s.sourceURL}:${s.sourceCharPosition}`,
layoutMs: Math.round(s.forcedStyleAndLayoutDuration),
kompilierMs: Math.round(compile)
});
});
}).observe({ type: 'long-animation-frame', buffered: true });
Blockierzeit pro Drittanbieter-Domain summieren (RUM)
const blockzeitProHost = new Map();
const observer = new PerformanceObserver((list) => {
for (const frame of list.getEntries()) {
for (const script of frame.scripts) {
if (!script.sourceURL) continue;
const host = new URL(script.sourceURL).host;
blockzeitProHost.set(host, (blockzeitProHost.get(host) ?? 0) + script.duration);
}
}
});
if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
observer.observe({ type: 'long-animation-frame', buffered: true });
addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
const daten = JSON.stringify(Object.fromEntries(blockzeitProHost));
navigator.sendBeacon('/rum/loaf', daten);
}
});
}