Start · Sprachen · JavaScript · Referenz · ReadableStream.cancel()

ReadableStream.cancel()

Methode

Bricht einen <code>ReadableStream</code> ab, verwirft alle gepufferten Daten und gibt ein Promise zurück, das nach Abschluss des Abbruchs aufgelöst wird.

seit JavaScript Baseline: alle modernen Browser, Node.js 18+ (glob Kategorie: webapi

Signatur

ReadableStream.prototype.cancel(reason)

Beschreibung

Mit cancel() teilt der Konsument einer Datenquelle mit, dass er keine weiteren Daten mehr benötigt. Der Stream wird geschlossen, alle noch in der internen Warteschlange liegenden Chunks werden verworfen, und die cancel(reason)-Funktion der zugrunde liegenden Quelle (underlying source) wird mit dem übergebenen Grund aufgerufen. So kann die Quelle Ressourcen freigeben, z. B. eine Netzwerkverbindung schließen oder einen Timer stoppen.

Typische Einsatzfälle: Man hat in einer fetch()-Antwort bereits die gesuchten Bytes gefunden und will den Rest nicht mehr herunterladen, ein Benutzer bricht einen Download ab, oder eine Komponente wird abgebaut und soll laufende Streams sauber beenden.

Wichtig: cancel() funktioniert direkt am Stream nur, wenn dieser nicht gesperrt ist (stream.locked === false). Hat bereits ein Reader den Stream übernommen, muss stattdessen reader.cancel() aufgerufen werden. Im Unterschied zu reader.releaseLock() beendet cancel() den Stream endgültig – er kann danach nicht mehr gelesen werden.

Parameter

Name Typ Default Beschreibung
$reason any undefined Beliebiger Grund für den Abbruch (z. B. ein String oder Error). Er wird an die cancel()-Funktion der zugrunde liegenden Quelle weitergereicht, die ihn auswerten kann.

Rückgabewert

Typ
Promise<undefined>
Beschreibung
Ein Promise, das mit undefined erfüllt wird, sobald die Quelle den Abbruch verarbeitet hat. Es wird mit einem TypeError abgelehnt, wenn der Stream gesperrt ist, oder mit dem Fehler, den die cancel()-Funktion der Quelle wirft.

Beispiele

Eigenen Stream abbrechen und Ressourcen freigeben

let timerId;
const stream = new ReadableStream({
  start(controller) {
    let i = 0;
    timerId = setInterval(() => controller.enqueue(`Tick ${i++}`), 100);
  },
  cancel(reason) {
    // Aufräumen, sobald der Konsument abbricht
    clearInterval(timerId);
    console.log('Quelle abgebrochen:', reason);
  }
});

await stream.cancel('Nicht mehr benötigt');
console.log('Stream beendet, gesperrt?', stream.locked);
Quelle abgebrochen: Nicht mehr benötigt Stream beendet, gesperrt? false

fetch-Download vorzeitig abbrechen über den Reader

const response = await fetch('https://example.com/grosse-datei.txt');
const reader = response.body.getReader();
const decoder = new TextDecoder();
let text = '';

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  text += decoder.decode(value, { stream: true });
  if (text.includes('ENDE-HEADER')) {
    // Gesperrter Stream: Abbruch über den Reader, nicht über response.body
    await reader.cancel('Gesuchter Abschnitt gefunden');
    break;
  }
}
console.log('Gelesen:', text.length, 'Zeichen');
Gelesen: 16384 Zeichen

Fehler bei gesperrtem Stream

const stream = new ReadableStream({
  start(controller) { controller.enqueue('Daten'); }
});
const reader = stream.getReader();

try {
  await stream.cancel();
} catch (err) {
  console.log(err.name); // Stream ist durch den Reader gesperrt
}

reader.releaseLock();
await stream.cancel('jetzt klappt es');
console.log('Abgebrochen');
TypeError Abgebrochen

// Wichtig · Fallstricke

  • Gesperrte Streams: Ist stream.locked true (z. B. nach getReader() oder während pipeTo()), lehnt cancel() mit TypeError ab. Dann reader.cancel() verwenden bzw. bei Pipes ein AbortSignal an pipeTo() übergeben.
  • Datenverlust: Alle noch gepufferten Chunks werden verworfen. Wer die Daten noch braucht, sollte zuerst fertig lesen.
  • Kein Fehlerzustand: Ein abgebrochener Stream gilt als geschlossen, nicht als fehlerhaft; ausstehende read()-Aufrufe liefern { done: true, value: undefined }.
  • Getee-Streams: Nach tee() wird die ursprüngliche Quelle erst abgebrochen, wenn beide Zweige abgebrochen wurden.
  • fetch: Das Abbrechen von response.body beendet den Download; für das Abbrechen der gesamten Anfrage ist AbortController meist die bessere Wahl.
  • Kompatibilität: in allen aktuellen Browsern verfügbar; in Node.js global ab Version 18 (vorher über stream/web).