Signatur
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 einPromisemit 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
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');
}
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));
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);
}
// 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 globalThisund sieh einen Ausweichweg übersetTimeoutoderMessageChannelvor. Alternativ kannst du ein Polyfill wiescheduler-polyfillnutzen. - Es gibt keinen Konstruktor:
new Scheduler()wirft einenTypeError. - 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
AbortErrorabgelehnt. Fange das ab, sonst entstehen unbehandelte Ablehnungen (unhandled rejections). priorityund einTaskSignalmit eigener Priorität schließen sich aus: Im Zweifel gewinnt die explizitepriority, undsetPriority()hat dann keine Wirkung."background"-Tasks können auf ausgelasteten Seiten sehr lange warten. Für zeitkritische Arbeit sind sie ungeeignet.