Start · Sprachen · JavaScript · Referenz · IdleDeadline

IdleDeadline

Schnittstelle

Das Objekt, das Leerlauf-Callbacks von <code>requestIdleCallback()</code> erhalten – es verrät, wie viel Leerlaufzeit noch bleibt und ob das Zeitlimit abgelaufen ist.

seit JavaScript Chrome 47+, Firefox 55+, Edge 79+, Safari: nicht u Kategorie: webapi

Signatur

interface IdleDeadline

Beschreibung

IdleDeadline ist der Datentyp des einzigen Parameters, den der Browser an einen mit window.requestIdleCallback() registrierten Callback übergibt. Selbst erzeugt man solche Objekte nie – sie werden ausschließlich vom Browser bereitgestellt, wenn der Haupt-Thread gerade nichts zu tun hat (etwa zwischen zwei Frames oder wenn keine Benutzereingaben anstehen).

Das Interface hat zwei Mitglieder:

  • timeRemaining() – Methode, die als DOMHighResTimeStamp (Millisekunden, Gleitkommazahl) zurückgibt, wie viel Zeit in der aktuellen Leerlaufphase schätzungsweise noch verbleibt. Der Wert liegt höchstens bei 50 ms und fällt auf 0, sobald die Phase vorbei ist.
  • didTimeout – schreibgeschützte boolesche Eigenschaft. Sie ist true, wenn der Callback nicht wegen echter Leerlaufzeit, sondern deshalb ausgeführt wird, weil das beim Registrieren angegebene timeout abgelaufen ist.

Typischerweise nutzt man IdleDeadline, um niedrig priorisierte Arbeit – Analytics-Daten versenden, Vorab-Berechnungen, Cache-Aufwärmen, Indexierung – in kleine Häppchen zu zerlegen. In einer Schleife wird so lange abgearbeitet, wie timeRemaining() > 0 gilt (oder didTimeout gesetzt ist); verbleibende Aufgaben werden per erneutem requestIdleCallback() auf die nächste Leerlaufphase verschoben. So bleibt die Seite flüssig und reaktionsfähig.

Rückgabewert

Typ
IdleDeadline
Beschreibung
Wird nicht zurückgegeben, sondern vom Browser als Argument an den Leerlauf-Callback übergeben. Mitglieder: timeRemaining(): number und didTimeout: boolean.

Beispiele

Grundlagen: IdleDeadline im Callback auslesen

requestIdleCallback((deadline) => {
  console.log(deadline instanceof IdleDeadline);
  console.log('Restzeit (ms):', deadline.timeRemaining().toFixed(2));
  console.log('Timeout erreicht?', deadline.didTimeout);
});
true Restzeit (ms): 49.80 Timeout erreicht? false

Aufgaben-Warteschlange in Leerlaufphasen abarbeiten

const tasks = Array.from({ length: 1000 }, (_, i) => () => Math.sqrt(i) * Math.random());
let processed = 0;

const processTasks = (deadline) => {
  // Arbeiten, solange Zeit bleibt oder das Timeout erzwungen wurde
  while ((deadline.timeRemaining() > 1 || deadline.didTimeout) && tasks.length > 0) {
    const task = tasks.shift();
    task();
    processed++;
  }

  if (tasks.length > 0) {
    // Rest in der nächsten Leerlaufphase erledigen
    requestIdleCallback(processTasks, { timeout: 2000 });
  } else {
    console.log(`Fertig: ${processed} Aufgaben verarbeitet`);
  }
};

requestIdleCallback(processTasks, { timeout: 2000 });
Fertig: 1000 Aufgaben verarbeitet

Analytics-Events gebündelt im Leerlauf senden

const queue = [];
let scheduled = false;

const track = (event) => {
  queue.push({ ...event, ts: Date.now() });
  if (!scheduled) {
    scheduled = true;
    requestIdleCallback(flush, { timeout: 5000 });
  }
};

const flush = (deadline) => {
  const batch = [];
  while (queue.length && (deadline.timeRemaining() > 0 || deadline.didTimeout)) {
    batch.push(queue.shift());
  }
  if (batch.length) {
    navigator.sendBeacon('/analytics', JSON.stringify(batch));
    console.log(`${batch.length} Events gesendet${deadline.didTimeout ? ' (per Timeout)' : ''}`);
  }
  scheduled = queue.length > 0;
  if (scheduled) requestIdleCallback(flush, { timeout: 5000 });
};

track({ type: 'pageview', path: location.pathname });
track({ type: 'click', target: 'cta-button' });
2 Events gesendet

Fallback für Browser ohne requestIdleCallback (z. B. Safari)

const ric = window.requestIdleCallback ?? ((cb) => {
  const start = performance.now();
  // Nachgebautes IdleDeadline-ähnliches Objekt
  return setTimeout(() => cb({
    didTimeout: false,
    timeRemaining: () => Math.max(0, 50 - (performance.now() - start))
  }), 1);
});

ric((deadline) => {
  console.log('Restzeit:', Math.round(deadline.timeRemaining()), 'ms');
});
Restzeit: 49 ms

// Wichtig · Fallstricke

  • Browser-Unterstützung: Chrome/Edge und Firefox unterstützen IdleDeadline; Safari bietet requestIdleCallback standardmäßig nicht an. Immer per Feature-Erkennung ('requestIdleCallback' in window) prüfen und einen Fallback mit setTimeout bereithalten.
  • timeRemaining() ist dynamisch: Der Wert sinkt während der Ausführung. Ihn nur einmal am Anfang zu lesen und dann lange zu arbeiten, untergräbt den Zweck. Vor jeder Teilaufgabe erneut abfragen.
  • Maximal 50 ms: Auch bei völlig untätigem Browser liefert timeRemaining() nie mehr als 50 ms, damit Benutzereingaben schnell bedient werden können.
  • didTimeout === true heißt nicht „Zeit vorhanden“: In diesem Fall gibt timeRemaining() meist 0 zurück. Nur das Nötigste erledigen, sonst entstehen Ruckler.
  • Keine DOM-Änderungen im Idle-Callback: Layout-Änderungen können die Frame-Planung stören und erzwungene Reflows auslösen. DOM-Arbeiten lieber per requestAnimationFrame() einplanen.
  • Promise-Auflösungen im Callback laufen sofort nach seinem Ende und können die Leerlaufphase überschreiten.
  • In Hintergrund-Tabs werden Idle-Callbacks stark gedrosselt oder gar nicht ausgeführt – ohne timeout kann Arbeit sehr lange liegen bleiben.