Start · Sprachen · JavaScript · Referenz · ReadableStreamDefaultController.close()

ReadableStreamDefaultController.close()

Methode

Schließt den zugehörigen <code>ReadableStream</code>. Bereits eingereihte Chunks können noch gelesen werden, danach meldet der Leser <code>done: true</code>.

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

Signatur

ReadableStreamDefaultController.prototype.close()

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-close oder 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

Typ
void
Beschreibung
Gibt 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');
a b c 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');
Chunk 1 Chunk 2 Chunk 3 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);
    }
  }
});
TypeError

// Wichtig · Fallstricke

  • TypeError: close() wirft einen TypeError, 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 nach cancel() durch den Konsumenten. In ereignisgesteuertem Code ruft man close() daher nur einmal auf, z. B. mit einem eigenen Flag. Alternativ vorher controller.desiredSize !== null prüfen: Bei einem Stream im Fehlerzustand ist der Wert null.
  • Nach close() führt auch enqueue() zu einem TypeError.
  • close() ist nicht dasselbe wie ReadableStream.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 stattdessen ReadableByteStreamController.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 mit for await über einen ReadableStream wird von Safari erst in neueren Versionen unterstützt. Als Ausweichlösung dient getReader().