Signatur
Beschreibung
Die schreibgeschützte Eigenschaft closed eines ReadableStreamDefaultReader gibt ein Promise<undefined> zurück. Mit diesem Promise lässt sich das Ende eines Streams beobachten, ohne die Leseschleife selbst auszuwerten. Das Promise wird erfüllt, sobald der Stream vollständig geschlossen ist, also nach controller.close() und nachdem alle Chunks in der Warteschlange gelesen wurden. Es wird abgelehnt, wenn der Stream in einen Fehlerzustand gerät, zum Beispiel durch controller.error() oder einen Netzwerkabbruch.
Es gibt noch einen zweiten Grund für eine Ablehnung: Gibt man die Sperre mit reader.releaseLock() frei, bevor der Stream geschlossen ist, wird closed mit einem TypeError abgelehnt. Der Reader ist dann nicht mehr mit dem Stream verbunden.
Typische Einsatzfälle:
- Aufräumarbeiten nach dem Ende eines Downloads, etwa eine Fortschrittsanzeige ausblenden
- Zentrale Fehlerbehandlung unabhängig von der Leseschleife
- Feststellen, ob ein Reader noch gültig ist
Die Eigenschaft gibt bei jedem Zugriff dasselbe Promise-Objekt zurück. Man kann also beliebig viele Handler daran hängen.
Rückgabewert
undefined erfüllt wird, wenn der Stream geschlossen ist. Es wird mit dem Fehlergrund des Streams abgelehnt oder mit einem TypeError, wenn die Sperre des Readers freigegeben wurde.Beispiele
Auf das Ende eines Streams warten
const stream = new ReadableStream({
start(controller) {
controller.enqueue('Hallo');
controller.enqueue('Welt');
controller.close();
}
});
const reader = stream.getReader();
const leseAlles = async () => {
while (true) {
const { value, done } = await reader.read();
if (done) break;
console.log('Chunk:', value);
}
await reader.closed; // erfüllt, weil der Stream geschlossen ist
console.log('Stream geschlossen');
};
leseAlles();
Stream-Fehler zentral abfangen
const stream = new ReadableStream({
start(controller) {
controller.enqueue('Teil 1');
setTimeout(() => controller.error(new Error('Verbindung abgebrochen')), 100);
}
});
const reader = stream.getReader();
reader.closed
.then(() => console.log('Fertig'))
.catch((err) => console.error('Stream-Fehler:', err.message));
const lesen = async () => {
try {
while (true) {
const { value, done } = await reader.read();
if (done) break;
console.log(value);
}
} catch {
// Fehler wird bereits über reader.closed behandelt
}
};
lesen();
Download-Ende bei fetch() erkennen
const ladeMitFortschritt = async (url) => {
const response = await fetch(url);
const reader = response.body.getReader();
let bytes = 0;
reader.closed
.then(() => console.log(`Download abgeschlossen: ${bytes} Bytes`))
.catch((err) => console.error('Download fehlgeschlagen:', err));
while (true) {
const { value, done } = await reader.read();
if (done) break;
bytes += value.byteLength;
}
};
ladeMitFortschritt('https://example.com/');
Ablehnung nach releaseLock()
const stream = new ReadableStream({
start(controller) {
controller.enqueue('Daten');
}
});
const reader = stream.getReader();
reader.closed.catch((err) => {
console.log(err.name); // Sperre wurde freigegeben
});
reader.releaseLock();
// Der Stream ist wieder frei und kann neu gesperrt werden
const neuerReader = stream.getReader();
console.log(stream.locked);
// Wichtig · Fallstricke
- Unbehandelte Ablehnungen: Schlägt der Stream fehl oder wird die Sperre freigegeben, wird
closedabgelehnt. Das passiert auch dann, wenn der Code das Promise nie benutzt. Werclosedabfragt, sollte deshalb immer einen.catch()-Handler anhängen. Sonst erscheinen Warnungen wegen unbehandelter Ablehnungen (unhandledrejection) in der Konsole bzw. in Node.js. - Keine Daten im Promise:
closedwird mitundefinederfüllt. Die Daten selbst muss man weiterhin überread()lesen. - Wartende Chunks: Nach
controller.close()ist der Stream erst dann geschlossen, wenn alle Chunks in der Warteschlange gelesen wurden. Wer nie liest, wartet also unter Umständen ewig aufclosed. - Abbruch: Nach
reader.cancel()wirdclosederfüllt, nicht abgelehnt. - Kompatibilität: Wird von allen modernen Browsern unterstützt (Chrome, Edge, Firefox, Safari), außerdem in Web Workers und in Node.js über
stream/webbzw. global ab Node.js 18. Das gleichnamige Promise gibt es auch beiReadableStreamBYOBReader.closedundWritableStreamDefaultWriter.closed.