Start · Sprachen · JavaScript · Referenz · Scheduler

Scheduler

Schnittstelle

Das <code>Scheduler</code>-Interface der Prioritized Task Scheduling API plant priorisierte Aufgaben mit <code>postTask()</code> und gibt den Hauptthread mit <code>yield()</code> kurz frei.

seit JavaScript Chromium 94+ (postTask), Chromium 129+ (yield), Fi Kategorie: webapi

Signatur

interface Scheduler

Beschreibung

Mit dem Scheduler-Interface lassen sich Aufgaben (Tasks) im Hauptthread nach ihrer Priorität einplanen. Es gibt keinen Konstruktor: Die einzige Instanz erreichst du über die globale Eigenschaft scheduler (window.scheduler bzw. self.scheduler in Workern).

Die Schnittstelle hat zwei Methoden:

  • scheduler.postTask(callback, options) plant einen Callback mit einer der Prioritäten "user-blocking", "user-visible" (Standard) oder "background" ein. Der Rückgabewert ist ein Promise mit dem Ergebnis des Callbacks.
  • scheduler.yield() gibt die Kontrolle an den Browser zurück, damit er z. B. Eingaben verarbeiten oder neu zeichnen kann. Danach läuft der Code mit erhöhter Priorität weiter, also vor anderen Tasks gleicher Priorität.

Sinnvoll ist das vor allem, wenn lange Berechnungen die Reaktionszeit der Seite verschlechtern (Stichwort Long Tasks und INP). Du teilst die Arbeit in kleine Stücke auf und planst unwichtige Arbeit wie Analytics oder Prefetching mit "background" ein. Wichtige Arbeit, etwa die Antwort auf eine Nutzereingabe, bekommt "user-blocking".

Über TaskController und TaskSignal kannst du geplante Tasks abbrechen und ihre Priorität auch nachträglich ändern.

Parameter

Name Typ Default Beschreibung
$callback Pflicht Function Parameter von postTask(): die auszuführende Funktion. Ihr Rückgabewert (auch ein Promise) löst das Ergebnis-Promise auf.
$options.priority "user-blocking" | "user-visible" | "background" "user-visible" Feste Priorität des Tasks. Du kannst sie nicht zusammen mit einem TaskSignal angeben, das selbst eine Priorität trägt.
$options.signal AbortSignal | TaskSignal Signal zum Abbrechen und, bei einem TaskSignal, zum dynamischen Ändern der Priorität.
$options.delay number 0 Mindestverzögerung in Millisekunden, bevor der Task in die Warteschlange kommt.

Rückgabewert

Typ
Promise<any> (postTask) | Promise<void> (yield)
Beschreibung
postTask() liefert ein Promise mit dem Rückgabewert des Callbacks. Wurde der Task abgebrochen, wird es mit einem AbortError abgelehnt. yield() liefert ein Promise, das erfüllt wird, sobald die Ausführung fortgesetzt werden soll.

Beispiele

Zugriff auf die Instanz und Tasks mit Prioritäten planen

if ('scheduler' in globalThis) {
  // Es gibt keinen Konstruktor – die Instanz ist global verfügbar
  const s = globalThis.scheduler;

  s.postTask(() => console.log('Hintergrund'), { priority: 'background' });
  s.postTask(() => console.log('Sichtbar'));
  s.postTask(() => console.log('Blockierend'), { priority: 'user-blocking' });
} else {
  console.log('Prioritized Task Scheduling API nicht verfügbar');
}
Blockierend Sichtbar Hintergrund

Lange Schleife mit scheduler.yield() zerlegen

const yieldToMain = () =>
  globalThis.scheduler?.yield
    ? scheduler.yield()
    : new Promise((resolve) => setTimeout(resolve, 0));

const processItems = async (items) => {
  let deadline = performance.now() + 50;
  const results = [];
  for (const item of items) {
    results.push(item * 2); // teure Arbeit simuliert
    if (performance.now() > deadline) {
      await yieldToMain(); // Browser darf Eingaben verarbeiten
      deadline = performance.now() + 50;
    }
  }
  return results;
};

processItems([1, 2, 3]).then((r) => console.log(r));
[2, 4, 6]

Rückgabewert, Verzögerung und Abbruch per TaskController

const controller = new TaskController({ priority: 'background' });

const task = scheduler.postTask(() => 'Analytics gesendet', {
  signal: controller.signal,
  delay: 2000,
});

// Priorität nachträglich anheben
controller.setPriority('user-visible');

// Nutzer verlässt die Ansicht: Task abbrechen
controller.abort();

try {
  console.log(await task);
} catch (err) {
  console.log(err.name);
}
AbortError

// Wichtig · Fallstricke

  • Browser-Unterstützung: postTask() gibt es seit Chromium 94, yield() seit Chromium 129. Firefox unterstützt beide seit Version 142, Safari noch gar nicht. Prüfe deshalb immer mit 'scheduler' in globalThis und sieh einen Ausweichweg über setTimeout oder MessageChannel vor. Alternativ kannst du ein Polyfill wie scheduler-polyfill nutzen.
  • Es gibt keinen Konstruktor: new Scheduler() wirft einen TypeError.
  • Die Prioritäten beeinflussen nur die Reihenfolge der Tasks untereinander. Einen einzelnen langen Task unterbrechen sie nicht, deshalb solltest du lange Arbeit trotzdem in Stücke teilen.
  • Wenn du ein Signal abbrichst, wird das Promise mit AbortError abgelehnt. Fange das ab, sonst entstehen unbehandelte Ablehnungen (unhandled rejections).
  • priority und ein TaskSignal mit eigener Priorität schließen sich aus: Im Zweifel gewinnt die explizite priority, und setPriority() hat dann keine Wirkung.
  • "background"-Tasks können auf ausgelasteten Seiten sehr lange warten. Für zeitkritische Arbeit sind sie ungeeignet.