Start · Sprachen · JavaScript · Referenz · AbortController.signal

AbortController.signal

Eigenschaft

Liefert das <code>AbortSignal</code>, das zum Controller gehört und an abbrechbare asynchrone Vorgänge wie <code>fetch()</code> übergeben wird.

seit JavaScript Baseline: alle modernen Browser (seit 2019), Node. Kategorie: webapi

Signatur

get AbortController.prototype.signal

Beschreibung

Die schreibgeschützte Eigenschaft signal gibt das AbortSignal-Objekt zurück, das fest mit einer AbortController-Instanz verbunden ist. Der Controller ist die „Sender-Seite“ und löst den Abbruch über abort() aus. Das Signal ist die „Empfänger-Seite“, die man an asynchrone Vorgänge weitergibt.

Man übergibt das Signal zum Beispiel an fetch(url, { signal }), an addEventListener(type, handler, { signal }), an Streams (pipeTo) oder an viele Node.js-APIs (fs.readFile, setTimeout aus timers/promises, events.once). Sobald controller.abort(reason) aufgerufen wird, wechselt signal.aborted auf true, signal.reason wird gesetzt und am Signal wird ein abort-Event ausgelöst.

Für jeden Controller gibt es immer dasselbe Signal-Objekt: Mehrfaches Lesen von controller.signal liefert dieselbe Instanz. Ein einmal abgebrochenes Signal lässt sich nicht zurücksetzen. Für einen neuen Vorgang braucht man einen neuen AbortController.

So kann man mehrere Vorgänge mit einem einzigen Signal gemeinsam abbrechen. Ein typischer Fall ist das Aufräumen aller Anfragen und Event-Listener, wenn eine Komponente entfernt wird.

Rückgabewert

Typ
AbortSignal
Beschreibung
Das mit dem Controller verknüpfte AbortSignal. Es hat die Eigenschaften aborted und reason, die Methode throwIfAborted() und das Event abort.

Beispiele

fetch-Anfrage abbrechen

const controller = new AbortController();
const { signal } = controller;

const ladeDaten = async () => {
  try {
    const res = await fetch('https://jsonplaceholder.typicode.com/posts', { signal });
    const daten = await res.json();
    console.log('Geladen:', daten.length);
  } catch (err) {
    if (err.name === 'AbortError') {
      console.log('Anfrage wurde abgebrochen');
    } else {
      throw err;
    }
  }
};

ladeDaten();
// z. B. wenn der Nutzer auf „Abbrechen“ klickt:
controller.abort();
Anfrage wurde abgebrochen

Mehrere Event-Listener auf einmal entfernen

const controller = new AbortController();

window.addEventListener('resize', () => console.log('resize'), { signal: controller.signal });
window.addEventListener('scroll', () => console.log('scroll'), { signal: controller.signal });
document.addEventListener('keydown', (e) => console.log(e.key), { signal: controller.signal });

// Aufräumen, z. B. beim Entfernen einer Komponente:
const aufraeumen = () => controller.abort();
aufraeumen();
console.log(controller.signal.aborted);
true

Eigene abbrechbare Funktion mit Abbruchgrund

const warte = (ms, signal) => new Promise((resolve, reject) => {
  signal?.throwIfAborted();
  const id = setTimeout(resolve, ms, 'fertig');
  signal?.addEventListener('abort', () => {
    clearTimeout(id);
    reject(signal.reason);
  }, { once: true });
});

const controller = new AbortController();
setTimeout(() => controller.abort(new Error('Zeitlimit des Nutzers')), 500);

try {
  console.log(await warte(2000, controller.signal));
} catch (err) {
  console.log('Abgebrochen:', err.message);
}
console.log(controller.signal === controller.signal);
Abgebrochen: Zeitlimit des Nutzers true

// Wichtig · Fallstricke

  • Schreibgeschützt: controller.signal = … wird im nicht-strikten Modus stillschweigend ignoriert und wirft im strikten Modus einen TypeError.
  • Nicht wiederverwendbar: Ein abgebrochenes Signal bleibt abgebrochen. Übergibt man es an ein neues fetch(), wird dieses sofort mit einem AbortError abgelehnt. Für jeden neuen Versuch einen neuen Controller anlegen.
  • Ruft man abort(reason) mit einem eigenen Grund auf, lehnt fetch() mit genau diesem Wert ab, nicht mit einem AbortError. Die Prüfung auf err.name === 'AbortError' greift dann nicht. Ohne Argument ist reason eine DOMException namens AbortError.
  • Für reine Zeitlimits ist AbortSignal.timeout(ms) einfacher, der Fehler heißt dann TimeoutError. Mehrere Signale kombiniert man mit AbortSignal.any([...]), das neuer ist und die Kompatibilität prüfen lässt.
  • Eigene abort-Listener am Signal wieder entfernen oder { once: true } nutzen, besonders bei langlebigen Signalen. Sonst drohen Speicherlecks.
  • Kompatibilität: in allen modernen Browsern verfügbar. reason und throwIfAborted() gibt es erst seit etwa 2022. In Node.js ist das Signal global verfügbar (stabil ab Version 15).