Start · Sprachen · JavaScript · Referenz · Window.requestIdleCallback()

Window.requestIdleCallback()

Methode

Reiht eine Funktion in eine Warteschlange ein, die der Browser in Leerlaufphasen der Ereignisschleife aufruft, ohne Animationen und Eingaben zu bremsen.

seit JavaScript Chrome 47+, Firefox 55+, Edge 79+, Safari: ab 18.x Kategorie: webapi

Signatur

window.requestIdleCallback(callback, options)

Beschreibung

requestIdleCallback() plant eine Funktion so ein, dass der Browser sie erst ausführt, wenn der Hauptthread gerade nichts zu tun hat, meist am Ende eines Frames oder wenn keine Eingaben, kein Layout und keine Animationen anstehen. So lassen sich unwichtige Hintergrundarbeiten wie Analytics-Daten senden, Daten vorladen, Caches aufwärmen oder große Datenmengen häppchenweise verarbeiten, ohne dass Scrollen, Tippen oder Animationen ruckeln.

Die Callback-Funktion bekommt ein IdleDeadline-Objekt übergeben. Dessen Methode timeRemaining() gibt an, wie viele Millisekunden in der aktuellen Leerlaufphase noch übrig sind (höchstens 50 ms). Die Eigenschaft didTimeout ist true, wenn der Callback nur deshalb läuft, weil das angegebene timeout abgelaufen ist. Üblich ist, in einer Schleife so lange Arbeitspakete abzuarbeiten, wie timeRemaining() größer als 0 ist, und für den Rest einen neuen Callback anzufordern.

Es gibt keine Garantie, dass der Callback überhaupt aufgerufen wird. Bei dauerhaft ausgelastetem Hauptthread oder in Hintergrund-Tabs kann er sehr lange warten. Für Arbeit, die spätestens nach einer bestimmten Zeit erledigt sein muss, gibt man die Option timeout an. Mit cancelIdleCallback(id) lässt sich ein geplanter Callback wieder abbrechen.

Parameter

Name Typ Default Beschreibung
$callback Pflicht (deadline: IdleDeadline) => void Funktion, die in einer Leerlaufphase aufgerufen wird. Sie erhält ein IdleDeadline-Objekt mit timeRemaining() und didTimeout.
$options { timeout?: number } {} Optionales Objekt. timeout (in Millisekunden): Ist der Callback bis dahin noch nicht gelaufen, wird er beim nächsten Durchlauf der Ereignisschleife auf jeden Fall ausgeführt, auch wenn das die Leistung beeinträchtigt.

Rückgabewert

Typ
number
Beschreibung
Eine ganzzahlige ID ungleich 0, mit der sich der Callback über window.cancelIdleCallback(id) abbrechen lässt.

Beispiele

Einfacher Hintergrund-Task mit Timeout

const id = requestIdleCallback((deadline) => {
  console.log('Leerlauf erreicht, Restzeit:', Math.round(deadline.timeRemaining()), 'ms');
  console.log('Wegen Timeout ausgelöst?', deadline.didTimeout);
}, { timeout: 2000 });

console.log('Geplant mit ID', id);
Geplant mit ID 1 Leerlauf erreicht, Restzeit: 49 ms Wegen Timeout ausgelöst? false

Große Warteschlange häppchenweise abarbeiten

const queue = Array.from({ length: 10000 }, (_, i) => i);
const results = [];

const processQueue = (deadline) => {
  // Arbeiten, solange Zeit übrig ist oder der Timeout gegriffen hat
  while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && queue.length > 0) {
    const item = queue.shift();
    results.push(item * item);
  }

  if (queue.length > 0) {
    requestIdleCallback(processQueue, { timeout: 1000 });
  } else {
    console.log('Fertig:', results.length, 'Einträge verarbeitet');
  }
};

requestIdleCallback(processQueue, { timeout: 1000 });
Fertig: 10000 Einträge verarbeitet

Analytics-Ereignisse gesammelt senden, mit Fallback

// Fallback für Browser ohne requestIdleCallback (z. B. Safari)
const idle = window.requestIdleCallback ??
  ((cb) => setTimeout(() => cb({ didTimeout: false, timeRemaining: () => 0 }), 1));

const pending = [];
let scheduled = false;

const track = (event) => {
  pending.push({ event, ts: Date.now() });
  if (!scheduled) {
    scheduled = true;
    idle(() => {
      navigator.sendBeacon('/analytics', JSON.stringify(pending.splice(0)));
      scheduled = false;
    }, { timeout: 3000 });
  }
};

track('page_view');
track('button_click');

Geplanten Callback abbrechen

const id = requestIdleCallback(() => {
  console.log('Vorladen gestartet');
});

// Benutzer verlässt die Ansicht, Vorladen nicht mehr nötig
cancelIdleCallback(id);
console.log('Callback', id, 'abgebrochen');
Callback 1 abgebrochen

// Wichtig · Fallstricke

  • Browser-Kompatibilität: Chrome, Edge und Firefox unterstützen die Methode schon lange. In Safari ist sie standardmäßig nicht verfügbar, daher vorher prüfen ('requestIdleCallback' in window) und auf setTimeout zurückfallen.
  • Keine DOM-Änderungen im Callback: Der Callback läuft am Ende eines Frames, wenn das Layout schon berechnet ist. DOM-Änderungen lösen dann ein erneutes Layout aus und können das Zeitbudget überschreiten. DOM-Updates besser mit requestAnimationFrame() einplanen.
  • Zeitbudget beachten: timeRemaining() liefert höchstens 50 ms. Lang laufende Einzelaufgaben, auch Promise-Auflösungen mit viel Arbeit, blockieren trotzdem den Hauptthread.
  • Timeout sparsam einsetzen: Mit timeout wird der Callback notfalls auch mitten in Lastphasen erzwungen. Dann ist didTimeout true und timeRemaining() meist 0. Den Code so schreiben, dass er in diesem Fall trotzdem sinnvoll arbeitet.
  • In Hintergrund-Tabs werden Callbacks unter Umständen stark verzögert (oft nur etwa einmal pro 10 s). Für Arbeit, die garantiert erledigt werden muss (z. B. vor dem Schließen der Seite), ist die Methode nicht geeignet. Dafür lieber visibilitychange mit navigator.sendBeacon() nutzen.
  • Die Methode gibt es auch in Web Workern nicht überall. Neuere Alternative mit Prioritäten: scheduler.postTask() (Prioritized Task Scheduling API, noch nicht in allen Browsern).