Signatur
Beschreibung
Mit close() teilt die Quelle eines ReadableStream mit, dass keine weiteren Daten mehr kommen. Der Controller wird als controller-Argument an die Callbacks start(), pull() und cancel() der Underlying Source übergeben. Nur über ihn lässt sich der Stream von innen schließen.
Der Stream wird dabei nicht sofort beendet. Chunks, die schon mit enqueue() in die interne Warteschlange gelegt wurden, bleiben erhalten und können weiter gelesen werden. Erst wenn die Warteschlange leer ist, geht der Stream in den Zustand closed über. Dann liefert reader.read() den Wert { value: undefined, done: true }, und das Promise reader.closed wird erfüllt.
Wann man close() aufruft:
- Eine Datenquelle ist erschöpft, z. B. ein Array ist vollständig durchlaufen oder ein Generator ist fertig.
- In
pull()wird das Ende der Daten erkannt. - Ein Ereignis signalisiert das Ende, z. B.
WebSocket-closeoder das Ende einer Server-Sent-Events-Verbindung.
Soll der Stream mit einem Fehler enden, verwendet man stattdessen controller.error(reason). Dabei werden die noch gepufferten Chunks verworfen.
Rückgabewert
undefined zurück.Beispiele
Stream aus einem Array erzeugen und schließen
const createArrayStream = (items) => new ReadableStream({
start(controller) {
for (const item of items) {
controller.enqueue(item);
}
// Keine weiteren Daten – Stream schließen
controller.close();
}
});
const stream = createArrayStream(['a', 'b', 'c']);
for await (const chunk of stream) {
console.log(chunk);
}
console.log('fertig');
Schließen in pull(), wenn die Quelle erschöpft ist
let counter = 0;
const stream = new ReadableStream({
pull(controller) {
counter += 1;
if (counter > 3) {
controller.close();
return;
}
controller.enqueue(`Chunk ${counter}`);
}
});
const reader = stream.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) break;
console.log(value);
}
await reader.closed;
console.log('Stream geschlossen');
WebSocket-Nachrichten als Stream, Schließen beim close-Event
const socketToStream = (url) => {
const ws = new WebSocket(url);
return new ReadableStream({
start(controller) {
ws.addEventListener('message', (e) => controller.enqueue(e.data));
ws.addEventListener('close', () => controller.close());
ws.addEventListener('error', () => controller.error(new Error('WebSocket-Fehler')));
},
cancel() {
ws.close();
}
});
};
const stream = socketToStream('wss://echo.example.org');
for await (const msg of stream) {
console.log('Nachricht:', msg);
}
Doppeltes Schließen abfangen
new ReadableStream({
start(controller) {
controller.enqueue('x');
controller.close();
try {
controller.close();
} catch (err) {
console.log(err.name);
}
}
});
// Wichtig · Fallstricke
- TypeError:
close()wirft einenTypeError, wenn der Stream schon geschlossen ist, schon geschlossen werden soll oder in einem Fehlerzustand ist. Das Gleiche gilt, wenn er nicht mehr lesbar ist, etwa nachcancel()durch den Konsumenten. In ereignisgesteuertem Code ruft manclose()daher nur einmal auf, z. B. mit einem eigenen Flag. Alternativ vorhercontroller.desiredSize !== nullprüfen: Bei einem Stream im Fehlerzustand ist der Wertnull. - Nach
close()führt auchenqueue()zu einemTypeError. close()ist nicht dasselbe wieReadableStream.prototype.cancel():close()ruft die Quelle auf, gepufferte Daten bleiben lesbar.cancel()ruft der Konsument auf, gepufferte Daten werden verworfen.- Bei Byte-Streams (
type: 'bytes') gibt es stattdessenReadableByteStreamController.close(). Steht dort noch eine BYOB-Anfrage mit teilweise gefülltem Puffer aus, wird ein Fehler ausgelöst. - Kompatibilität: Unterstützt von allen modernen Browsern (Chrome, Edge, Firefox 65+, Safari). In Node.js ab Version 18 global verfügbar, davor über
stream/web. Die asynchrone Iteration mitfor awaitüber einenReadableStreamwird von Safari erst in neueren Versionen unterstützt. Als Ausweichlösung dientgetReader().