Signatur
Beschreibung
Die schreibgeschützte Eigenschaft windowAttribution eines PerformanceScriptTiming-Eintrags gibt an, in welcher Beziehung der Container eines Skripts zum Dokument steht, in dem der Eintrag erfasst wurde. Container ist dabei das Dokument der obersten Ebene oder ein <iframe>. Die Einträge stammen aus der Long Animation Frames API (LoAF). Man findet sie im Array scripts jedes PerformanceLongAnimationFrameTiming-Eintrags.
Mögliche Werte:
"self": Das Skript lief im aktuellen Dokument selbst."descendant": Das Skript lief in einem untergeordneten Frame, z. B. einem eingebetteten iframe."ancestor": Das Skript lief in einem übergeordneten Frame, also in einem Dokument, das das aktuelle Dokument einbettet."same-page": Das Skript lief in einem anderen Frame derselben Seite, der weder über- noch untergeordnet ist, z. B. in einem Geschwister-iframe."other": Das Skript lief in einem Fenster, das nicht zur selben Seite gehört, z. B. in einem perwindow.open()geöffneten Fenster derselben Herkunft, das sich denselben Event-Loop teilt.
Mit dieser Eigenschaft lässt sich erkennen, woher ein Skript stammt, das einen Frame blockiert hat. Typisch ist die Frage, ob eingebettete Werbe- oder Widget-iframes die Reaktionsfähigkeit der eigenen Seite (INP) verschlechtern. Zusammen mit PerformanceScriptTiming.window bekommt man bei Bedarf auch eine direkte Referenz auf das betroffene Fenster.
Rückgabewert
Beispiele
Herkunft blockierender Skripte protokollieren
const observer = new PerformanceObserver((list) => {
for (const frame of list.getEntries()) {
for (const script of frame.scripts) {
console.log(
`${script.windowAttribution}: ${script.sourceURL || '(inline)'} ` +
`– ${Math.round(script.duration)} ms`
);
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
Blockierzeit nach Container gruppieren
const totals = { self: 0, descendant: 0, ancestor: 0, 'same-page': 0, other: 0 };
new PerformanceObserver((list) => {
for (const frame of list.getEntries()) {
for (const { windowAttribution, duration } of frame.scripts) {
totals[windowAttribution] += duration;
}
}
}).observe({ type: 'long-animation-frame', buffered: true });
// Später, z. B. beim Verlassen der Seite, an das Monitoring senden
addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon('/rum', JSON.stringify(totals));
}
});
Nur iframe-Skripte mit Fensterreferenz auswerten
new PerformanceObserver((list) => {
const fremd = list.getEntries()
.flatMap((frame) => frame.scripts)
.filter((s) => s.windowAttribution === 'descendant');
for (const s of fremd) {
// s.window ist null, wenn kein Zugriff möglich ist (z. B. fremde Herkunft)
const frameEl = s.window?.frameElement;
console.warn('Langsames iframe-Skript:', s.invoker, frameEl?.id ?? '(unbekannt)');
}
}).observe({ type: 'long-animation-frame', buffered: true });
// Wichtig · Fallstricke
- Kompatibilität: Die Eigenschaft gehört zur Long Animation Frames API und wird bisher nur von Chromium-Browsern unterstützt (ab Chrome/Edge 123). Prüfe die Unterstützung vorher mit
PerformanceObserver.supportedEntryTypes.includes('long-animation-frame'). - Erfasst werden nur Skripte, die sich einen Event-Loop mit dem aktuellen Dokument teilen. iframes einer fremden Herkunft laufen oft in einem eigenen Prozess und erscheinen dann gar nicht in den Einträgen.
- Bei Skripten aus Frames einer fremden Herkunft sind Details wie
sourceURLaus Datenschutzgründen oft leer.windowkannnullsein. - Außerdem werden nur Skripte mit einer Dauer über 5 ms innerhalb eines langen Animationsframes (über 50 ms) aufgenommen. Kurze Skripte fehlen also.
- Die Werte hängen immer vom Blickwinkel des beobachtenden Dokuments ab. Dasselbe Skript kann in einem anderen Frame als
"ancestor"statt"descendant"erscheinen.