Start · Sprachen · JavaScript · Referenz · PerformanceScriptTiming.invoker

PerformanceScriptTiming.invoker

Eigenschaft

Schreibgeschützte Zeichenkette, die angibt, welches Feature (Skript-URL, Event-Listener, Callback oder Promise) ein Skript innerhalb eines langen Animationsframes aufgerufen hat.

seit JavaScript Chromium 123+ (Chrome, Edge, Opera); nicht in Fire Kategorie: webapi

Signatur

PerformanceScriptTiming.invoker

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 Format TAGNAME#id.onereignis bzw. 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

Typ
string
Beschreibung
Eine Zeichenkette, die das aufrufende Feature beschreibt (Skript-URL, Element-/Ereignis-Bezeichner, API-Name oder Promise-Quelle). Wie sie aufgebaut ist, hängt von 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 });
event-listener → BUTTON#speichern.onclick (142 ms) user-callback → Window.setTimeout (63 ms) classic-script → https://cdn.example.com/tracker.js (88 ms)

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) })));
  }
});
┌─────────┬───────────────────────────┬─────┐ │ (index) │ invoker │ ms │ │ 0 │ 'BUTTON#speichern.onclick'│ 284 │ │ 1 │ 'INPUT#suche.oninput' │ 97 │ └─────────┴───────────────────────────┴─────┘

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 invokerType ab 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 scripts landen 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 sourceURL oder sourceFunctionName. invoker ist dann oft der einzige Hinweis auf die Ursache.
  • Elemente ohne id werden bei Event-Listenern nur über den Tag-Namen (und ggf. src) angegeben. Vergib aussagekräftige IDs, damit die Auswertung eindeutig ist.