Signatur
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
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);
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');
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');
// Wichtig · Fallstricke
- Gesperrte Streams: Ist
stream.lockedtrue(z. B. nachgetReader()oder währendpipeTo()), lehntcancel()mitTypeErrorab. Dannreader.cancel()verwenden bzw. bei Pipes einAbortSignalanpipeTo()ü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.bodybeendet den Download; für das Abbrechen der gesamten Anfrage istAbortControllermeist die bessere Wahl. - Kompatibilität: in allen aktuellen Browsern verfügbar; in Node.js global ab Version 18 (vorher über
stream/web).