Start · Sprachen · JavaScript · Referenz · ReadableStream.getReader()

ReadableStream.getReader()

Methode

Erstellt einen Leser (<code>ReadableStreamDefaultReader</code> oder <code>ReadableStreamBYOBReader</code>) und sperrt den Stream exklusiv für diesen Leser.

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

Signatur

ReadableStream.prototype.getReader(options)

Beschreibung

Mit getReader() holst du dir einen Leser, über den du die Datenstücke (Chunks) eines ReadableStream einzeln abrufst. Solange der Leser aktiv ist, ist der Stream gesperrt (stream.locked === true). Kein anderer Leser kann dann darauf zugreifen, und auch pipeTo(), pipeThrough() oder tee() lassen sich nicht aufrufen.

Ohne Argument bekommst du einen ReadableStreamDefaultReader. Dessen Methode read() liefert ein Promise auf { value, done }. Mit { mode: "byob" } („bring your own buffer“) bekommst du einen ReadableStreamBYOBReader. Dieser schreibt Bytes direkt in einen Puffer, den du selbst bereitstellst. Das spart Speicherkopien, funktioniert aber nur bei Byte-Streams (type: "bytes").

Typische Einsätze: Fortschrittsanzeigen beim Download über response.body, Verarbeiten großer Dateien in Stücken oder das Einlesen gestreamter Serverantworten (z. B. von LLM-APIs). Gib den Leser nach der Verarbeitung mit reader.releaseLock() frei, wenn der Stream danach noch anderweitig genutzt werden soll.

Parameter

Name Typ Default Beschreibung
$options { mode?: "byob" } {} Optionales Objekt. Mit mode: "byob" entsteht ein ReadableStreamBYOBReader. Fehlt mode oder ist es undefined, entsteht ein ReadableStreamDefaultReader.

Rückgabewert

Typ
ReadableStreamDefaultReader | ReadableStreamBYOBReader
Beschreibung
Ein Leser, der den Stream bis zum Aufruf von releaseLock() exklusiv sperrt.

Beispiele

Download mit Fortschrittsanzeige

const downloadWithProgress = async (url) => {
  const response = await fetch(url);
  const total = Number(response.headers.get('Content-Length')) || 0;
  const reader = response.body.getReader();
  const chunks = [];
  let received = 0;

  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    chunks.push(value);
    received += value.length;
    if (total) console.log(`Fortschritt: ${Math.round((received / total) * 100)} %`);
  }

  return new Blob(chunks);
};

const blob = await downloadWithProgress('/dateien/video.mp4');
console.log('Fertig:', blob.size, 'Bytes');
Fortschritt: 12 % Fortschritt: 47 % ... Fertig: 5242880 Bytes

Gestreamten Text dekodieren und Sperre freigeben

const stream = new ReadableStream({
  start(controller) {
    const enc = new TextEncoder();
    controller.enqueue(enc.encode('Hallo, '));
    controller.enqueue(enc.encode('Stream!'));
    controller.close();
  }
});

const reader = stream.getReader();
console.log(stream.locked);

const decoder = new TextDecoder();
let text = '';
try {
  for (;;) {
    const { value, done } = await reader.read();
    if (done) break;
    text += decoder.decode(value, { stream: true });
  }
  text += decoder.decode(); // restliche Bytes ausgeben
} finally {
  reader.releaseLock();
}

console.log(text);
console.log(stream.locked);
true Hallo, Stream! false

BYOB-Leser mit eigenem Puffer

const stream = new ReadableStream({
  type: 'bytes',
  start(controller) {
    controller.enqueue(new Uint8Array([1, 2, 3, 4, 5, 6]));
    controller.close();
  }
});

const reader = stream.getReader({ mode: 'byob' });
let buffer = new ArrayBuffer(4);

while (true) {
  const { value, done } = await reader.read(new Uint8Array(buffer));
  if (done) break;
  console.log([...value]);
  buffer = value.buffer; // Puffer wurde übertragen – weiterverwenden
}
[1, 2, 3, 4] [5, 6]

Fehler bei doppelter Sperre

const stream = new ReadableStream();
const r1 = stream.getReader();

try {
  stream.getReader();
} catch (err) {
  console.log(err.name);
}

r1.releaseLock();
const r2 = stream.getReader(); // jetzt möglich
console.log(stream.locked);
TypeError true

// Wichtig · Fallstricke

  • Nur ein Leser gleichzeitig: Ist der Stream schon gesperrt, wirft getReader() einen TypeError. Prüfe vorher stream.locked oder nutze tee(), wenn zwei Abnehmer die Daten brauchen.
  • BYOB nur bei Byte-Streams: { mode: "byob" } bei einem Stream ohne type: "bytes" führt zu einem TypeError. Ein ungültiger mode-Wert ebenfalls.
  • Puffer wird übertragen: Beim BYOB-Lesen wird der übergebene ArrayBuffer abgetrennt (detached). Arbeite danach mit value.buffer weiter.
  • Sperre freigeben: Ohne releaseLock() bleibt der Stream gesperrt. releaseLock() ist auch bei offenen read()-Promises erlaubt. Diese werden dann abgelehnt (neueres Verhalten der Spezifikation; ältere Browser warfen stattdessen einen Fehler).
  • Abbrechen: reader.cancel() bricht den Stream ab und gibt der Quelle Ressourcen frei, z. B. bei einem abgebrochenen Download.
  • Alternative: In neueren Umgebungen (Node.js, Firefox 110+, Chrome 124+, Safari 26.4+) lassen sich Streams direkt mit for await (const chunk of stream) durchlaufen. Die Sperre wird dabei automatisch gesetzt und wieder freigegeben.
  • Content-Length: Bei komprimierten Antworten (gzip) passt dieser Header oft nicht zur Menge der dekodierten Bytes. Die Fortschrittsanzeige kann dann ungenau sein.