Start · Sprachen · JavaScript · Referenz · AbortSignal.any()

AbortSignal.any()

Methode

Fasst mehrere <code>AbortSignal</code>-Objekte zu einem neuen Signal zusammen, das abbricht, sobald irgendeines der Eingangssignale abbricht.

seit JavaScript Baseline 2024: Chrome 116, Firefox 124, Safari 17. Kategorie: webapi

Signatur

AbortSignal.any(iterable)

Beschreibung

Die statische Methode AbortSignal.any() nimmt ein iterierbares Objekt (z. B. ein Array) von AbortSignal-Instanzen entgegen und gibt ein neues AbortSignal zurück. Dieses abhängige Signal wechselt in den abgebrochenen Zustand, sobald eines der übergebenen Signale abbricht. Sein reason ist dann der Abbruchgrund genau dieses ersten abgebrochenen Signals.

Typisch ist die Kombination verschiedener Abbruchquellen, etwa ein benutzergesteuerter Abbruch über einen AbortController und ein Zeitlimit über AbortSignal.timeout(). Früher musste man dafür Event-Listener von Hand verdrahten und später wieder aufräumen. AbortSignal.any() erledigt das sauber und ohne Speicherlecks.

Ist beim Aufruf bereits eines der Eingangssignale abgebrochen, ist auch das zurückgegebene Signal sofort abgebrochen. Es übernimmt dann den reason des ersten abgebrochenen Signals in der Reihenfolge der Iteration. Das kombinierte Signal lässt sich überall einsetzen, wo ein signal erwartet wird, zum Beispiel bei fetch(), addEventListener() oder bei Streams.

Parameter

Name Typ Default Beschreibung
$iterable Pflicht Iterable<AbortSignal> Ein iterierbares Objekt, z. B. ein Array oder ein Set, das AbortSignal-Instanzen enthält. Ein leeres Iterable ist erlaubt und ergibt ein Signal, das nie abbricht.

Rückgabewert

Typ
AbortSignal
Beschreibung
Ein neues AbortSignal, das abbricht, sobald eines der Eingangssignale abbricht. Sein reason entspricht dem Grund dieses Signals. Ist bereits beim Aufruf ein Eingangssignal abgebrochen, ist auch das Rückgabesignal sofort abgebrochen.

Beispiele

Fetch mit Benutzerabbruch und Zeitlimit

const controller = new AbortController();
document.querySelector('#cancel')?.addEventListener('click', () => controller.abort());

const loadData = async () => {
  const signal = AbortSignal.any([
    controller.signal,          // Abbruch durch den Benutzer
    AbortSignal.timeout(5000)   // spätestens nach 5 Sekunden
  ]);

  try {
    const res = await fetch('/api/daten', { signal });
    return await res.json();
  } catch (err) {
    if (err.name === 'TimeoutError') {
      console.log('Zeitlimit überschritten');
    } else if (err.name === 'AbortError') {
      console.log('Vom Benutzer abgebrochen');
    } else {
      throw err;
    }
  }
};

loadData();
Zeitlimit überschritten (wenn der Server länger als 5 s braucht)

Abbruchgrund des ersten Signals wird übernommen

const a = new AbortController();
const b = new AbortController();

const combined = AbortSignal.any([a.signal, b.signal]);
combined.addEventListener('abort', () => {
  console.log('Abgebrochen:', combined.reason);
});

b.abort('Grund B');
a.abort('Grund A'); // hat keine Wirkung mehr auf combined

console.log(combined.aborted);
Abgebrochen: Grund B true

Bereits abgebrochenes Eingangssignal

const done = AbortSignal.abort('schon erledigt');
const live = new AbortController();

const signal = AbortSignal.any([live.signal, done]);
console.log(signal.aborted, signal.reason);
true schon erledigt

Event-Listener an Komponenten- und Seitenlebensdauer koppeln

const pageController = new AbortController();

const mountWidget = (el) => {
  const widgetController = new AbortController();
  const signal = AbortSignal.any([pageController.signal, widgetController.signal]);

  // Listener wird automatisch entfernt, wenn eines der Signale abbricht
  window.addEventListener('resize', () => {
    el.textContent = `Breite: ${window.innerWidth}px`;
  }, { signal });

  return () => widgetController.abort(); // Aufräumfunktion
};

const unmount = mountWidget(document.body);
// später: unmount();  oder  pageController.abort();

// Wichtig · Fallstricke

  • Browserunterstützung: Erst seit 2024 in allen großen Browsern verfügbar (Chrome/Edge 116, Firefox 124, Safari 17.4) und in Node.js ab 20.3. Für ältere Umgebungen per Feature-Erkennung prüfen: if ('any' in AbortSignal) { … }. Andernfalls mit einem eigenen AbortController und abort-Listenern nachbauen.
  • Das Rückgabesignal ist unabhängig. Es hat keinen eigenen Controller, lässt sich also nicht direkt abbrechen. Wer es auch manuell abbrechen will, nimmt zusätzlich das Signal eines eigenen AbortController in die Liste auf.
  • Der Abbruch wirkt nur in eine Richtung: Bricht das kombinierte Signal ab, bleiben die Eingangssignale unverändert.
  • Welcher Fehler geworfen wird, hängt vom reason ab. AbortSignal.timeout() führt zu TimeoutError, controller.abort() ohne Argument zu AbortError. Beim Fehlerhandling beide Fälle unterscheiden.
  • Wird ein Element übergeben, das kein AbortSignal ist, wirft die Methode einen TypeError.
  • Browser geben abhängige Signale frei, wenn sie nicht mehr gebraucht werden. Trotzdem sollte man in Schleifen keine unnötig vielen kombinierten Signale auf langlebigen Quellsignalen erzeugen.