Signatur
Beschreibung
Die Eigenschaft invoker gehört zur Long Animation Frames API (LoAF). Jeder Eintrag vom Typ long-animation-frame enthält im Array scripts Objekte vom Typ PerformanceScriptTiming. Jedes dieser Objekte beschreibt ein Skript, das zu einem langen Frame beigetragen hat. invoker zeigt dabei an, wer das Skript gestartet hat.
Der Inhalt hängt vom Wert von invokerType ab:
"classic-script"/"module-script": die URL des Skripts, z. B."https://example.com/app.js", bei Inline-Skripten die URL des Dokuments."event-listener": Element und Ereignis im FormatTAGNAME#id.onereignisbzw.TAGNAME[src=…].onereignis, z. B."BUTTON#speichern.onclick"oder"IMG[src=https://example.com/bild.png].onload"."user-callback": die aufrufende Plattform-API, z. B."Window.setTimeout"oder"Window.requestAnimationFrame"."resolve-promise"/"reject-promise": die Promise-Quelle, z. B."Window.fetch.then"oder"Response.json.then".
Nützlich ist invoker vor allem beim Real User Monitoring (RUM): Du kannst damit auswerten, welche Event-Handler, Timer oder Drittanbieter-Skripte die Seite blockieren und die Interaktionsgeschwindigkeit (INP) verschlechtern. Zusammen mit sourceURL, sourceFunctionName und duration lässt sich die Ursache meist genau eingrenzen.
Rückgabewert
invokerType ab.Beispiele
Aufrufer langer Skripte 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)`
);
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
Langsame Event-Handler gezielt finden
const langsameHandler = new Map();
new PerformanceObserver((list) => {
for (const frame of list.getEntries()) {
frame.scripts
.filter((s) => s.invokerType === 'event-listener')
.forEach((s) => {
const bisher = langsameHandler.get(s.invoker) ?? 0;
langsameHandler.set(s.invoker, bisher + s.duration);
});
}
}).observe({ type: 'long-animation-frame', buffered: true });
// Später, z. B. beim Verlassen der Seite:
addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
console.table([...langsameHandler].map(([invoker, ms]) => ({ invoker, ms: Math.round(ms) })));
}
});
Drittanbieter-Skripte per RUM melden (mit Feature-Erkennung)
if (PerformanceObserver.supportedEntryTypes?.includes('long-animation-frame')) {
new PerformanceObserver((list) => {
const daten = list.getEntries().flatMap((frame) =>
frame.scripts
.filter((s) => !s.sourceURL.startsWith(location.origin))
.map((s) => ({
invoker: s.invoker,
invokerType: s.invokerType,
quelle: s.sourceURL,
dauer: Math.round(s.duration)
}))
);
if (daten.length) {
navigator.sendBeacon('/rum/loaf', JSON.stringify(daten));
}
}).observe({ type: 'long-animation-frame', buffered: true });
} else {
console.info('Long Animation Frames API wird nicht unterstützt.');
}
// Wichtig · Fallstricke
- Browser-Kompatibilität: Bisher gibt es die Eigenschaft nur in Chromium-Browsern (ab Version 123). Prüfe die Unterstützung vorher mit
PerformanceObserver.supportedEntryTypes.includes('long-animation-frame'). - Format ist nicht fest vorgegeben: Wie der Text aufgebaut ist, hängt von
invokerTypeab und kann sich zwischen Browserversionen ändern. Werte ihn deshalb nicht mit starren regulären Ausdrücken aus, sondern nutze ihn vor allem zum Gruppieren und Anzeigen. - Nicht alle Skripte erscheinen: In
scriptslanden nur Skripte, die länger als 5 ms laufen, und nur in Frames über 50 ms. - Cross-Origin: Bei Skripten von fremden Origins ohne CORS-Freigabe fehlen Details wie
sourceURLodersourceFunctionName.invokerist dann oft der einzige Hinweis auf die Ursache. - Elemente ohne
idwerden bei Event-Listenern nur über den Tag-Namen (und ggf.src) angegeben. Vergib aussagekräftige IDs, damit die Auswertung eindeutig ist.