Start · Sprachen · JavaScript · Referenz · PerformanceLongAnimationFrameTiming.blockingDuration

PerformanceLongAnimationFrameTiming.blockingDuration

Eigenschaft

Gibt als <code>DOMHighResTimeStamp</code> an, wie viele Millisekunden der Hauptthread in einem langen Animationsframe blockiert war und nicht auf Eingaben reagieren konnte.

seit JavaScript Chrome/Edge 123+ (nicht in Firefox und Safari) Kategorie: webapi

Signatur

PerformanceLongAnimationFrameTiming.blockingDuration

Beschreibung

Die schreibgeschützte Eigenschaft blockingDuration eines PerformanceLongAnimationFrameTiming-Eintrags (Long Animation Frames API, kurz LoAF) gibt an, wie lange der Hauptthread insgesamt blockiert war. In dieser Zeit konnte er nicht auf Aufgaben mit hoher Priorität wie Nutzereingaben reagieren. Der Wert ist eine Zahl in Millisekunden. Nachkommastellen sind möglich.

Berechnung: Der Browser nimmt alle langen Tasks innerhalb des Frames, also Tasks mit mehr als 50 ms Dauer, und zieht von jeder 50 ms ab. Die Renderzeit des Frames wird zur Dauer des längsten Tasks addiert. Die Summe dieser Werte ist blockingDuration. Ein Frame kann also lang sein (duration > 50 ms) und trotzdem eine blockingDuration von 0 haben, wenn er aus vielen kurzen Tasks besteht.

Die Eigenschaft eignet sich gut, um Probleme bei der Reaktionsfähigkeit zu finden, etwa als Ursache für schlechte Interaction to Next Paint-Werte (INP). Sie misst genauer als duration, wie stark Nutzer tatsächlich ausgebremst werden. Wer sie mit scripts, renderStart und styleAndLayoutStart kombiniert, findet heraus, welcher Code die Blockade verursacht.

Rückgabewert

Typ
DOMHighResTimeStamp (number)
Beschreibung
Blockierzeit des Frames in Millisekunden. Der Wert ist 0, wenn kein einzelner Task länger als 50 ms dauerte.

Beispiele

Blockierende Frames mit PerformanceObserver protokollieren

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > 0) {
      console.log(
        `Frame ${entry.duration.toFixed(0)} ms lang, davon ${entry.blockingDuration.toFixed(0)} ms blockierend`
      );
    }
  }
});

// buffered: true liefert auch Einträge, die vor dem Registrieren entstanden sind
observer.observe({ type: 'long-animation-frame', buffered: true });
Frame 142 ms lang, davon 87 ms blockierend

Gesamte Blockierzeit summieren und beim Verlassen der Seite senden

let totalBlocking = 0;
let worstFrame = null;

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    totalBlocking += entry.blockingDuration;
    if (!worstFrame || entry.blockingDuration > worstFrame.blockingDuration) {
      worstFrame = entry;
    }
  }
}).observe({ type: 'long-animation-frame', buffered: true });

document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    navigator.sendBeacon('/analytics/loaf', JSON.stringify({
      totalBlocking: Math.round(totalBlocking),
      worstBlocking: Math.round(worstFrame?.blockingDuration ?? 0),
      worstScripts: worstFrame?.scripts.map((s) => s.sourceURL) ?? []
    }));
  }
});

Verursachende Skripte des stärksten Blockers ermitteln

const frames = performance.getEntriesByType('long-animation-frame');

const top = frames
  .filter((f) => f.blockingDuration > 0)
  .sort((a, b) => b.blockingDuration - a.blockingDuration)[0];

if (top) {
  console.log(`Blockierend: ${top.blockingDuration.toFixed(1)} ms`);
  for (const script of top.scripts) {
    console.log(`${script.invoker} → ${script.sourceURL} (${script.duration.toFixed(0)} ms)`);
  }
} else {
  console.log('Keine blockierenden Frames gefunden');
}
Blockierend: 87.3 ms BUTTON#buy.onclick → https://example.com/app.js (120 ms)

// Wichtig · Fallstricke

  • Browser-Unterstützung: Nur in Chromium-Browsern ab Version 123 (Chrome, Edge, Opera). Firefox und Safari unterstützen die API nicht. Vor der Nutzung prüfen, ob der Browser sie kennt: PerformanceObserver.supportedEntryTypes.includes('long-animation-frame').
  • duration ist nicht gleich blockingDuration: Ein Frame mit vielen kurzen Tasks kann über 50 ms lang sein und trotzdem blockingDuration === 0 haben. Wer Reaktionsfähigkeit bewerten will, sollte blockingDuration auswerten.
  • Kein direkter TBT-Ersatz: Wegen der Renderzeit, die zum längsten Task addiert wird, weichen die Werte von der Total Blocking Time aus Lighthouse und der Long Tasks API ab.
  • Puffer-Grenze: performance.getEntriesByType() liefert nur begrenzt viele gepufferte Einträge. Zum fortlaufenden Messen einen PerformanceObserver verwenden.
  • Genauigkeit: Die Zeitauflösung kann aus Sicherheitsgründen gerundet sein (Schutz vor Timing-Angriffen). In Seiten ohne Cross-Origin-Isolation ist sie gröber.