Start · Sprachen · JavaScript · Referenz · TaskController

TaskController

Schnittstelle

Controller der Prioritized Task Scheduling API, mit dem sich über <code>scheduler.postTask()</code> geplante Aufgaben abbrechen und in ihrer Priorität ändern lassen.

seit JavaScript Chromium 94+ (Chrome, Edge, Opera), Firefox 142+; Kategorie: webapi

Signatur

interface TaskController extends AbortController

Beschreibung

TaskController gehört zur Prioritized Task Scheduling API und erweitert AbortController. Neben dem bekannten abort() kann er mit setPriority() die Priorität aller Aufgaben ändern, die mit seinem Signal verknüpft sind. Seine Eigenschaft signal ist ein TaskSignal (Unterklasse von AbortSignal). Dieses Signal hat zusätzlich die Eigenschaft priority und löst das Ereignis prioritychange aus.

Verwendet wird der Controller zusammen mit scheduler.postTask(callback, { signal }). Alle Aufgaben, die dasselbe Signal bekommen, bilden eine Gruppe: Ein einziger Aufruf von setPriority() stuft die ganze Gruppe hoch oder herunter, und ein abort() bricht alle Aufgaben ab, die noch nicht gestartet sind. Das Promise dieser abgebrochenen Aufgaben wird mit dem Abbruchgrund abgelehnt, standardmäßig einem DOMException vom Typ AbortError.

Typische Einsätze sind das Vorladen oder Vorberechnen von Daten mit niedriger Priorität ("background"). Braucht der Nutzer das Ergebnis plötzlich doch, stuft man die Gruppe auf "user-blocking" hoch. Wird es nicht mehr gebraucht, zum Beispiel beim Wechsel der Route in einer Single-Page-Anwendung, bricht man die Gruppe ab.

Es gibt drei Prioritäten: "user-blocking" (höchste), "user-visible" (Standard) und "background" (niedrigste).

Parameter

Name Typ Default Beschreibung
$options { priority?: "user-blocking" | "user-visible" | "background" } { priority: "user-visible" } Optionales Objekt für den Konstruktor new TaskController(options). priority legt die Anfangspriorität des zugehörigen TaskSignal fest.
$priority (setPriority) Pflicht "user-blocking" | "user-visible" | "background" Argument von controller.setPriority(priority): die neue Priorität für alle Aufgaben, die mit controller.signal verknüpft sind. Löst am Signal das Ereignis prioritychange aus.
$reason (abort) any DOMException "AbortError" Argument von controller.abort(reason) (von AbortController geerbt): der Abbruchgrund, mit dem die Promises der wartenden Aufgaben abgelehnt werden.

Rückgabewert

Typ
TaskController
Beschreibung
Der Konstruktor liefert eine neue TaskController-Instanz. Ihre Eigenschaft signal ist ein TaskSignal. setPriority() und abort() geben undefined zurück.

Beispiele

Controller erzeugen und Aufgabe planen

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

console.log(controller.signal.priority); // Anfangspriorität

const result = await scheduler.postTask(
  () => {
    // aufwendige Berechnung im Hintergrund
    return Array.from({ length: 1e5 }, (_, i) => i).reduce((a, b) => a + b, 0);
  },
  { signal: controller.signal }
);

console.log('Summe:', result);
background Summe: 4999950000

Priorität einer Aufgabengruppe nachträglich erhöhen

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

prefetch.signal.addEventListener('prioritychange', (event) => {
  console.log(`Priorität: ${event.previousPriority} → ${event.target.priority}`);
});

const loadArticle = (id) =>
  scheduler.postTask(
    () => fetch(`/api/articles/${id}`).then((r) => r.json()),
    { signal: prefetch.signal }
  );

const tasks = [1, 2, 3].map(loadArticle);

// Der Nutzer öffnet die Artikelliste, jetzt wird es dringend
document.querySelector('#articles-tab')?.addEventListener('click', () => {
  prefetch.setPriority('user-blocking');
});

const articles = await Promise.all(tasks);
console.log(articles.length, 'Artikel geladen');
Priorität: background → user-blocking 3 Artikel geladen

Wartende Aufgaben beim Routenwechsel abbrechen

const routeTasks = new TaskController();

const task = scheduler
  .postTask(() => console.log('Wird nie ausgeführt'), {
    signal: routeTasks.signal,
    delay: 1000
  })
  .catch((err) => console.log('Abgebrochen:', err.name));

// z. B. beim Verlassen der Seite in einer SPA
routeTasks.abort();

await task;
console.log('signal.aborted =', routeTasks.signal.aborted);
Abgebrochen: AbortError signal.aborted = true

Feature-Erkennung mit Rückfallebene

const runLowPriority = (fn) => {
  if ('scheduler' in globalThis && 'TaskController' in globalThis) {
    const controller = new TaskController({ priority: 'background' });
    return { controller, done: scheduler.postTask(fn, { signal: controller.signal }) };
  }
  // Rückfall: einfache Verzögerung per setTimeout
  const controller = new AbortController();
  const done = new Promise((resolve, reject) => {
    const id = setTimeout(() => resolve(fn()), 0);
    controller.signal.addEventListener('abort', () => {
      clearTimeout(id);
      reject(controller.signal.reason);
    });
  });
  return { controller, done };
};

const { done } = runLowPriority(() => 'fertig');
console.log(await done);
fertig

// Wichtig · Fallstricke

  • Browser-Kompatibilität: In Chromium-Browsern gibt es die API seit Version 94, in Firefox erst in neueren Versionen. Safari unterstützt sie nicht. Prüfe deshalb immer, ob 'TaskController' in globalThis gilt, und sieh einen Rückfall vor (z. B. setTimeout oder ein Polyfill).
  • Die Option priority in postTask() hat Vorrang: Übergibst du sowohl signal als auch priority, nutzt die Aufgabe die feste priority. Ein späteres setPriority() wirkt dann nicht auf sie; das Signal ist nur noch für den Abbruch zuständig.
  • setPriority() wirft einen NotAllowedError, wenn du es innerhalb eines prioritychange-Handlers desselben Signals aufrufst. Die Priorität zu setzen, die bereits gilt, bewirkt nichts und löst auch kein Ereignis aus.
  • abort() verhindert nur den Start wartender Aufgaben. Eine Callback-Funktion, die schon läuft, wird nicht unterbrochen. Bei längeren Aufgaben solltest du deshalb im Callback selbst signal.aborted prüfen oder signal.throwIfAborted() aufrufen.
  • Fange abgelehnte Promises abgebrochener Aufgaben ab. Sonst erscheinen Warnungen über unbehandelte Ablehnungen (unhandledrejection).
  • Einen abgebrochenen Controller kann man nicht wiederverwenden. Für eine neue Aufgabengruppe erzeugst du einen neuen TaskController.