Signatur
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
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');
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);
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
}
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);
// Wichtig · Fallstricke
- Nur ein Leser gleichzeitig: Ist der Stream schon gesperrt, wirft
getReader()einenTypeError. Prüfe vorherstream.lockedoder nutzetee(), wenn zwei Abnehmer die Daten brauchen. - BYOB nur bei Byte-Streams:
{ mode: "byob" }bei einem Stream ohnetype: "bytes"führt zu einemTypeError. Ein ungültigermode-Wert ebenfalls. - Puffer wird übertragen: Beim BYOB-Lesen wird der übergebene
ArrayBufferabgetrennt (detached). Arbeite danach mitvalue.bufferweiter. - Sperre freigeben: Ohne
releaseLock()bleibt der Stream gesperrt.releaseLock()ist auch bei offenenread()-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.