Signatur
Beschreibung
Der Konstruktor new AbortController() erzeugt einen Controller, der ein zugehöriges AbortSignal in der Eigenschaft signal bereitstellt. Dieses Signal gibt man an abbrechbare APIs weiter, zum Beispiel an fetch(), addEventListener(), Streams oder viele Node.js-Funktionen (fs.readFile, timers/promises, child_process).
Ein Aufruf von controller.abort(reason) setzt signal.aborted auf true, speichert den Grund in signal.reason und löst auf dem Signal das Ereignis abort aus. Alle Vorgänge, die das Signal beobachten, brechen dann ab. Bei fetch() wird das Promise mit einem DOMException namens AbortError abgelehnt, oder mit dem übergebenen Grund.
Typische Einsätze sind das Abbrechen veralteter Suchanfragen beim Tippen, das Aufräumen in React-useEffect-Hooks, das gebündelte Entfernen mehrerer Event-Listener und das Setzen eigener Zeitlimits. Ein Controller ist für genau einen Abbruch gedacht: Nach abort() bleibt das Signal dauerhaft abgebrochen, für neue Vorgänge braucht man einen neuen Controller.
Rückgabewert
AbortController-Instanz mit der Eigenschaft signal (ein noch nicht abgebrochenes AbortSignal) und der Methode abort(reason?).Beispiele
Fetch-Anfrage nach Zeitlimit abbrechen
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 3000);
try {
const response = await fetch('https://api.example.com/daten', {
signal: controller.signal,
});
const daten = await response.json();
console.log('Geladen:', daten);
} catch (err) {
if (err.name === 'AbortError') {
console.log('Anfrage abgebrochen (Zeitlimit)');
} else {
throw err;
}
} finally {
clearTimeout(timer);
}
Veraltete Suchanfragen beim Tippen verwerfen
let aktuellerController = null;
const suche = async (begriff) => {
aktuellerController?.abort(); // vorherige Anfrage abbrechen
aktuellerController = new AbortController();
const { signal } = aktuellerController;
try {
const res = await fetch(`/api/suche?q=${encodeURIComponent(begriff)}`, { signal });
const treffer = await res.json();
console.log(`Treffer für "${begriff}":`, treffer.length);
} catch (err) {
if (err.name !== 'AbortError') console.error(err);
}
};
document.querySelector('#suchfeld')
.addEventListener('input', (e) => suche(e.target.value));
Mehrere Event-Listener auf einmal entfernen
const controller = new AbortController();
const { signal } = controller;
window.addEventListener('resize', () => console.log('resize'), { signal });
window.addEventListener('scroll', () => console.log('scroll'), { signal });
document.addEventListener('keydown', (e) => console.log('Taste:', e.key), { signal });
// Später, z. B. beim Schließen einer Komponente:
controller.abort();
console.log(signal.aborted);
Eigenen Abbruchgrund übergeben und abfragen
const controller = new AbortController();
controller.signal.addEventListener('abort', () => {
console.log('Abgebrochen:', controller.signal.reason);
}, { once: true });
controller.abort('Benutzer hat abgebrochen');
controller.abort('zweiter Aufruf'); // wirkungslos
console.log(controller.signal.aborted);
// Wichtig · Fallstricke
- Nur einmal verwendbar: Ein abgebrochenes Signal bleibt abgebrochen. Wer es erneut an
fetch()übergibt, bekommt sofort eine Ablehnung. Deshalb pro Vorgang einen neuen Controller anlegen. - Fehler unterscheiden: Abbrüche kommen im
catchan. Miterr.name === 'AbortError'(bzw.'TimeoutError'beiAbortSignal.timeout()) erkennt man sie. Wirdabort(reason)mit einem eigenen Grund aufgerufen, lehntfetch()mit genau diesem Wert ab und nicht mit einemAbortError. - Kein echter Server-Abbruch: Der Abbruch beendet die Verbindung auf Clientseite. Hat der Server die Anfrage schon verarbeitet, etwa bei einem POST, sind ihre Nebenwirkungen trotzdem passiert.
- Kürzere Alternativen: Für reine Zeitlimits ist
AbortSignal.timeout(ms)einfacher. Mehrere Signale lassen sich mitAbortSignal.any([...])zusammenfassen (neuere Browser, Node.js 20+). - Eigene APIs: Wer selbst abbrechbare Funktionen schreibt, sollte zu Beginn
signal.throwIfAborted()aufrufen und denabort-Listener am Ende wieder entfernen, sonst entstehen Speicherlecks. - Kompatibilität: Läuft in allen aktuellen Browsern (Chrome 66+, Firefox 57+, Safari 12.1+, Edge 16+).
signal.reasonundabort(reason)gibt es erst seit etwa 2022. In Node.js ist der Konstruktor ab Version 15 global verfügbar. Im Internet Explorer fehlt er, dort braucht man ein Polyfill.