Signatur
Beschreibung
Der Konstruktor ReadableStreamBYOBReader() erzeugt einen Reader für einen Byte-Stream, also einen ReadableStream, der mit type: "bytes" angelegt wurde. Anders als der Standard-Reader bekommst du keine vom Stream erzeugten Chunks. Stattdessen übergibst du bei jedem read() eine eigene ArrayBufferView (z. B. Uint8Array), und der Stream schreibt die Bytes direkt dort hinein. So vermeidest du unnötige Kopien und Speicherzuweisungen, weil du einen Puffer immer wieder verwenden kannst.
Mit dem Erstellen wird der Stream gesperrt (stream.locked === true). Solange der Reader die Sperre hält, kann kein anderer Reader auf den Stream zugreifen. Mit reader.releaseLock() gibst du die Sperre wieder frei.
In der Praxis bekommst du einen solchen Reader meist über stream.getReader({ mode: "byob" }). Das ist gleichwertig zum direkten Aufruf des Konstruktors. BYOB-Reader eignen sich besonders für Binärprotokolle, Dateiformate mit festen Header-Größen und das Lesen großer Datenmengen mit wenig Speicher, etwa aus fetch()-Antworten (response.body ist ein Byte-Stream) oder aus eigenen Byte-Quellen.
Wichtig: Der Puffer, den du an read() übergibst, wird übertragen („transferred“) und ist danach abgekoppelt (detached). Arbeite deshalb immer mit value bzw. value.buffer aus dem Ergebnis weiter.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $stream Pflicht | ReadableStream | Der zu lesende Byte-Stream. Er muss mit type: "bytes" erzeugt worden sein (also einen ReadableByteStreamController haben) und darf noch nicht gesperrt sein. |
Rückgabewert
stream gebunden ist und ihn sperrt. Er bietet read(view), cancel(), releaseLock() und das Promise closed.Beispiele
Reader für einen eigenen Byte-Stream erzeugen
const stream = new ReadableStream({
type: "bytes",
start(controller) {
controller.enqueue(new Uint8Array([1, 2, 3, 4, 5]));
controller.close();
}
});
const reader = new ReadableStreamBYOBReader(stream);
console.log(stream.locked);
// Eigenen Puffer mit 8 Bytes bereitstellen
const { value, done } = await reader.read(new Uint8Array(8));
console.log(value, done);
reader.releaseLock();
console.log(stream.locked);
Genau N Bytes aus einer fetch-Antwort lesen (Puffer wiederverwenden)
const readExactly = async (reader, size) => {
let buffer = new ArrayBuffer(size);
let offset = 0;
while (offset < size) {
const { value, done } = await reader.read(
new Uint8Array(buffer, offset, size - offset)
);
if (value) {
// Der alte Puffer ist jetzt abgekoppelt, also mit dem zurückgegebenen weiterarbeiten
buffer = value.buffer;
offset += value.byteLength;
}
if (done) break;
}
return new Uint8Array(buffer, 0, offset);
};
const response = await fetch("/daten.bin");
const reader = new ReadableStreamBYOBReader(response.body);
// Beispiel: 16 Byte langen Datei-Header lesen
const header = await readExactly(reader, 16);
console.log(`Header: ${header.byteLength} Bytes`);
await reader.cancel(); // Rest wird nicht gebraucht
Fehlerfälle: kein Byte-Stream oder Stream schon gesperrt
const normalStream = new ReadableStream({
start(controller) {
controller.enqueue("Text");
controller.close();
}
});
try {
new ReadableStreamBYOBReader(normalStream);
} catch (err) {
console.log(err.name); // kein type: "bytes"
}
const byteStream = new ReadableStream({ type: "bytes" });
const first = byteStream.getReader({ mode: "byob" });
try {
new ReadableStreamBYOBReader(byteStream);
} catch (err) {
console.log(err.name); // schon gesperrt
}
// Wichtig · Fallstricke
- TypeError: Der Konstruktor wirft einen Fehler, wenn
streamkein Byte-Stream ist (also ohnetype: "bytes"erzeugt wurde) oder bereits gesperrt ist. Das prüfst du vorher mitstream.locked. - Abgekoppelte Puffer: Nach
read(view)istview.buffernicht mehr nutzbar (byteLength === 0). Verwende immerresult.value.bufferfür den nächsten Lesevorgang. - Teilweise gefüllt:
read()kann weniger Bytes liefern, als die übergebene View fasst. Brauchst du eine feste Anzahl, liest du in einer Schleife weiter (siehe Beispiel) oder nutzt in neueren Browsern die Optionread(view, { min }). - Die View darf nicht leer sein (
byteLength > 0), sonst wird das Promise mit einemTypeErrorabgelehnt. - Kompatibilität: Chromium hat Byte-Streams und BYOB-Reader seit Version 89, Firefox seit 102, Safari erst seit 18.4. In älteren Safari-Versionen ist
response.bodykein Byte-Stream. Mach dort eine Funktionsprüfung und falle aufgetReader()zurück. In Node.js stehen beide als Globals ab Version 18 zur Verfügung, vorher überstream/web.