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

ReadableStreamDefaultController.enqueue()

Methode

Reiht einen Chunk in die interne Warteschlange des zugehörigen <code>ReadableStream</code> ein, damit Konsumenten ihn lesen können.

seit JavaScript Baseline: alle modernen Browser (seit 2019), Node. Kategorie: webapi

Signatur

ReadableStreamDefaultController.prototype.enqueue(chunk)

Beschreibung

Mit enqueue() übergibt die Quelle eines ReadableStream Daten an den Stream. Der Controller wird der Quelle in den Callbacks start(controller) und pull(controller) des Underlying-Source-Objekts übergeben. Jeder Aufruf legt genau einen Chunk in die interne Warteschlange. Von dort holt ihn ein Leser (reader.read(), for await...of, pipeTo()) ab.

Ein Chunk kann ein beliebiger JavaScript-Wert sein: Strings, Objekte, Uint8Array usw. Wartet gerade ein Leser mit einem offenen read(), bekommt er den Chunk direkt. Sonst bleibt der Chunk in der Warteschlange, und controller.desiredSize sinkt um die Größe, die die queuingStrategy für ihn berechnet.

enqueue() wirft selbst keinen Druck zurück, der Aufruf gelingt also auch bei voller Warteschlange. Um Rückstau (Backpressure) zu beachten, sollte die Quelle desiredSize prüfen oder Daten nur in pull() liefern. pull() ruft der Stream erst auf, wenn wieder Platz ist.

Parameter

Name Typ Default Beschreibung
$chunk Pflicht any Der einzureihende Datenblock. Bei Byte-Streams (type: "bytes") wird stattdessen ReadableByteStreamController mit einer ArrayBufferView genutzt.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined).

Beispiele

Einfacher Stream aus festen Werten

const stream = new ReadableStream({
  start(controller) {
    controller.enqueue('Hallo');
    controller.enqueue('Welt');
    controller.close();
  }
});

for await (const chunk of stream) {
  console.log(chunk);
}
Hallo Welt

Pull-basierter Zähler mit Backpressure

let i = 0;
const zaehler = new ReadableStream({
  pull(controller) {
    // pull() wird nur aufgerufen, wenn der Stream mehr Daten will
    if (i < 3) {
      controller.enqueue(i++);
    } else {
      controller.close();
    }
  }
}, { highWaterMark: 1 });

const reader = zaehler.getReader();
let ergebnis;
while (!(ergebnis = await reader.read()).done) {
  console.log('Wert:', ergebnis.value);
}
Wert: 0 Wert: 1 Wert: 2

Timer-Ereignisse als Stream mit Abbruch

let timer;
const ticks = new ReadableStream({
  start(controller) {
    let n = 0;
    timer = setInterval(() => {
      controller.enqueue(`Tick ${++n}`);
      if (n === 3) {
        clearInterval(timer);
        controller.close();
      }
    }, 100);
  },
  cancel() {
    // wichtig: nach cancel() kein enqueue() mehr
    clearInterval(timer);
  }
});

const text = [];
for await (const t of ticks) text.push(t);
console.log(text.join(', '));
Tick 1, Tick 2, Tick 3

Text als Uint8Array für eine Response einreihen

const encoder = new TextEncoder();
const body = new ReadableStream({
  start(controller) {
    controller.enqueue(encoder.encode('{"status":'));
    controller.enqueue(encoder.encode('"ok"}'));
    controller.close();
  }
});

const daten = await new Response(body).json();
console.log(daten.status);
ok

// Wichtig · Fallstricke

  • TypeError: enqueue() wirft einen TypeError, wenn der Stream schon geschlossen wurde (close()), einen Fehlerzustand hat (error()) oder vom Konsumenten abgebrochen wurde (cancel()). Asynchrone Quellen wie Timer, WebSockets oder Event-Listener sollten deshalb im cancel()-Callback aufräumen.
  • Backpressure: enqueue() nimmt immer an, auch wenn desiredSize <= 0 ist. Wer das ignoriert, füllt bei schnellen Quellen den Speicher. Prüfe controller.desiredSize oder liefere Daten nur in pull().
  • Response-Bodys: Für new Response(stream) oder fetch-Uploads müssen die Chunks Uint8Array sein. Strings führen beim Lesen zu einem TypeError.
  • Byte-Streams: Bei type: "bytes" bekommt die Quelle einen ReadableByteStreamController statt eines ReadableStreamDefaultController.
  • Kompatibilität: Wird von allen modernen Browsern unterstützt. for await...of direkt über einen ReadableStream funktioniert in Safari erst seit neueren Versionen. Zur Sicherheit getReader() verwenden. In Node.js steht die API global ab Version 18 bereit, vorher über stream/web.