Start · Sprachen · JavaScript · Referenz · PerformanceScriptTiming.executionStart

PerformanceScriptTiming.executionStart

Eigenschaft

Gibt als <code>DOMHighResTimeStamp</code> an, wann die Kompilierung eines Skripts fertig war und seine Ausführung begann (schreibgeschützt).

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

Signatur

PerformanceScriptTiming.executionStart

Beschreibung

Die schreibgeschützte Eigenschaft executionStart gehört zum Interface PerformanceScriptTiming der Long Animation Frames API (LoAF). Sie enthält einen DOMHighResTimeStamp in Millisekunden, gemessen ab performance.timeOrigin. Der Wert gibt an, wann die Kompilierung des Skripts abgeschlossen war und die eigentliche Ausführung begonnen hat.

Zusammen mit der geerbten Eigenschaft startTime lässt sich ein Skript-Eintrag in zwei Phasen aufteilen:

  • Kompilierungs- bzw. Vorbereitungszeit: executionStart - startTime
  • Reine Ausführungszeit: (startTime + duration) - executionStart

An PerformanceScriptTiming-Objekte kommt man nicht direkt heran. Sie stecken im Array scripts eines PerformanceLongAnimationFrameTiming-Eintrags, den ein PerformanceObserver mit dem Typ "long-animation-frame" liefert. Die Eigenschaft hilft bei der Frage, ob ein langer Frame von großen, teuer zu parsenden Skript-Bundles kommt oder von aufwendiger Laufzeitlogik. Im ersten Fall helfen Code-Splitting und kleinere Bundles, im zweiten eher Aufteilen der Arbeit mit scheduler.yield() oder setTimeout.

Rückgabewert

Typ
DOMHighResTimeStamp (number)
Beschreibung
Zeitstempel in Millisekunden relativ zu performance.timeOrigin, zu dem die Skriptausführung nach der Kompilierung begann. Der Wert ist immer größer oder gleich startTime des Eintrags.

Beispiele

Kompilierungs- und Ausführungszeit langer Frames messen

const observer = new PerformanceObserver((list) => {
  for (const frame of list.getEntries()) {
    for (const script of frame.scripts) {
      const compile = script.executionStart - script.startTime;
      const execute = script.startTime + script.duration - script.executionStart;
      console.log(
        `${script.invoker}: Kompilierung ${compile.toFixed(1)} ms, ` +
        `Ausführung ${execute.toFixed(1)} ms`
      );
    }
  }
});

observer.observe({ type: 'long-animation-frame', buffered: true });
https://example.com/app.js: Kompilierung 18.4 ms, Ausführung 72.9 ms

Skripte mit hohem Kompilierungsanteil finden

const findeTeureBundles = (schwelleMs = 20) => {
  const frames = performance.getEntriesByType('long-animation-frame');
  return frames
    .flatMap((frame) => frame.scripts)
    .map((s) => ({
      quelle: s.sourceURL || s.invoker,
      kompilierung: Math.round(s.executionStart - s.startTime)
    }))
    .filter((s) => s.kompilierung >= schwelleMs)
    .sort((a, b) => b.kompilierung - a.kompilierung);
};

console.table(findeTeureBundles());
┌─────────┬──────────────────────────────────┬──────────────┐ │ (index) │ quelle │ kompilierung │ │ 0 │ 'https://cdn.example.com/vendor.js' │ 41 │ └─────────┴──────────────────────────────────┴──────────────┘

Mit Feature-Erkennung an ein RUM-Backend senden

const unterstuetzt = PerformanceObserver.supportedEntryTypes?.includes('long-animation-frame');

if (unterstuetzt) {
  new PerformanceObserver((list) => {
    const daten = list.getEntries().flatMap((frame) =>
      frame.scripts.map((s) => ({
        url: s.sourceURL,
        funktion: s.sourceFunctionName,
        executionStart: Math.round(s.executionStart),
        kompilierungMs: Math.round(s.executionStart - s.startTime)
      }))
    );
    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-Unterstützung: Die API gibt es bisher nur in Chromium-basierten Browsern (ab Version 123). Firefox und Safari unterstützen sie nicht. Vorher per PerformanceObserver.supportedEntryTypes prüfen, ob sie verfügbar ist.
  • Nur lange Skripte: In scripts landen nur Skripte, die länger als ca. 5 ms laufen und zu einem Frame von über 50 ms gehören. Kurze Skripte tauchen nicht auf.
  • Relativ zu timeOrigin: Der Wert ist keine Unix-Zeit. Für eine absolute Zeit muss performance.timeOrigin dazugerechnet werden.
  • Kompilierung nicht immer sichtbar: Bei Callbacks wie Event-Listenern oder Promise-Reaktionen ist der Code meist schon kompiliert. executionStart liegt dann sehr nah an startTime, der Unterschied sagt wenig aus.
  • Genauigkeit: Zum Schutz vor Timing-Angriffen runden Browser die Zeitstempel ab. Ohne Cross-Origin-Isolation ist die Auflösung gröber.
  • Datenschutz: Bei fremden (cross-origin) Frames oder Skripten gibt der Browser teilweise weniger Informationen heraus. Das kann z. B. die Zuordnung über windowAttribution betreffen.