Start · Sprachen · JavaScript · Referenz · ReadableStreamBYOBRequest

ReadableStreamBYOBRequest

Schnittstelle

Stellt eine Leseanforderung eines BYOB-Readers dar: Die zugrundeliegende Quelle schreibt Daten direkt in einen vom Verbraucher bereitgestellten Puffer und meldet dann per <code>respond()</code>, wie viele Bytes sie geschrieben hat.

seit JavaScript Baseline 2024: Chrome 89+, Edge 89+, Firefox 102+, Kategorie: webapi

Signatur

interface ReadableStreamBYOBRequest

Beschreibung

ReadableStreamBYOBRequest gehört zur Streams API und wird nur bei Byte-Streams verwendet, also bei einem ReadableStream, der mit type: "bytes" erzeugt wurde. BYOB steht für „Bring Your Own Buffer“: Der Verbraucher liest über einen ReadableStreamBYOBReader und übergibt dabei eigenen Speicher. Die Quelle schreibt ihre Daten direkt dort hinein. Das spart Zwischenkopien und Speicherzuweisungen, was bei großen Binärdaten wie Dateien, Netzwerkprotokollen oder Mediendaten spürbar hilft.

Du erzeugst keine Instanz selbst. Du bekommst sie in der pull()-Methode (oder in start()) der zugrundeliegenden Quelle über controller.byobRequest, wobei controller ein ReadableByteStreamController ist. Ist gerade keine Anforderung offen, ist der Wert null. Mit autoAllocateChunkSize legt der Stream auch für normale Default-Reader automatisch einen Puffer an. Dann gibt es immer eine byobRequest, und die Quelle braucht nur einen einzigen Codepfad.

Die Schnittstelle hat ein Attribut und zwei Methoden:

  • view: ein ArrayBufferView (in der Praxis ein Uint8Array), in das die Quelle schreiben soll, oder null, wenn die Anforderung schon erledigt ist.
  • respond(bytesWritten): meldet, dass bytesWritten Bytes in view geschrieben wurden.
  • respondWithNewView(view): übergibt stattdessen eine neue Ansicht auf denselben (übertragenen) Puffer, etwa wenn die Quelle den Puffer selbst übertragen hat.

Nach einem Aufruf von respond() oder respondWithNewView() ist die Anforderung erledigt. view wird null, und der Puffer geht an den Verbraucher zurück.

Parameter

Name Typ Default Beschreibung
$bytesWritten Pflicht number Parameter von respond(): Anzahl der Bytes, die ab view.byteOffset in view geschrieben wurden. Im Zustand „readable“ muss der Wert größer als 0 und höchstens view.byteLength sein. Nach controller.close() muss er 0 sein.
$view Pflicht ArrayBufferView Parameter von respondWithNewView(): neue Ansicht auf denselben zugrundeliegenden Speicher. byteOffset muss dem von byobRequest.view entsprechen, und die Pufferlänge muss gleich bleiben. byteLength gibt die Zahl der geschriebenen Bytes an.

Rückgabewert

Typ
void
Beschreibung
respond() und respondWithNewView() geben undefined zurück. Das Attribut view liefert ArrayBufferView | null.

Beispiele

Byte-Stream mit BYOB-Unterstützung (Zufallsdaten)

// Quelle, die direkt in den Puffer des Verbrauchers schreibt
let remaining = 64;

const stream = new ReadableStream({
  type: 'bytes',
  autoAllocateChunkSize: 16, // sorgt dafür, dass immer eine byobRequest existiert
  pull(controller) {
    const request = controller.byobRequest;
    const view = request.view; // Uint8Array
    const n = Math.min(view.byteLength, remaining);
    crypto.getRandomValues(view.subarray(0, n));
    remaining -= n;
    request.respond(n);
    if (remaining === 0) controller.close();
  }
});

const reader = stream.getReader({ mode: 'byob' });
let buffer = new ArrayBuffer(32);
let total = 0;
while (true) {
  const { value, done } = await reader.read(new Uint8Array(buffer));
  if (done) break;
  total += value.byteLength;
  buffer = value.buffer; // der übertragene Puffer wird wiederverwendet
}
console.log('Gelesen:', total, 'Bytes');
Gelesen: 64 Bytes

Fallback: byobRequest oder enqueue()

// Ohne autoAllocateChunkSize kann byobRequest null sein (Default-Reader)
const data = new TextEncoder().encode('Hallo Streams!');
let offset = 0;

const stream = new ReadableStream({
  type: 'bytes',
  pull(controller) {
    const request = controller.byobRequest;
    if (request) {
      const view = request.view;
      const n = Math.min(view.byteLength, data.length - offset);
      view.set(data.subarray(offset, offset + n));
      offset += n;
      request.respond(n);
    } else {
      controller.enqueue(data.slice(offset));
      offset = data.length;
    }
    if (offset >= data.length) controller.close();
  }
});

const reader = stream.getReader({ mode: 'byob' });
const { value } = await reader.read(new Uint8Array(5));
console.log(new TextDecoder().decode(value));
Hallo

respondWithNewView() mit Teilansicht

const stream = new ReadableStream({
  type: 'bytes',
  pull(controller) {
    const { view } = controller.byobRequest;
    view[0] = 0xCA;
    view[1] = 0xFE;
    // neue Ansicht: gleicher Puffer und Offset, aber nur 2 Bytes geschrieben
    const filled = new Uint8Array(view.buffer, view.byteOffset, 2);
    controller.byobRequest.respondWithNewView(filled);
  }
});

const reader = stream.getReader({ mode: 'byob' });
const { value } = await reader.read(new Uint8Array(8));
console.log([...value].map(b => b.toString(16)));
[ 'ca', 'fe' ]

// Wichtig · Fallstricke

  • Nur bei Byte-Streams: controller.byobRequest gibt es nur mit type: "bytes". Bei normalen Streams hat der Controller dieses Attribut nicht.
  • null prüfen: Liest der Verbraucher mit einem Default-Reader und ist kein autoAllocateChunkSize gesetzt, ist byobRequest null. Dann Daten mit controller.enqueue() einreihen.
  • Puffer werden übertragen: Der an reader.read(view) übergebene Puffer wird abgetrennt (transferiert). Danach nur noch über value.buffer darauf zugreifen, nicht über die alte Referenz.
  • Genau einmal antworten: Nach respond() ist view null. Ein zweiter Aufruf wirft einen TypeError. Auch ein controller.enqueue() erledigt die offene Anforderung.
  • Nach close(): Eine noch offene Anforderung muss mit respond(0) beantwortet werden. Andere Werte lösen einen TypeError aus. Umgekehrt gilt: Im offenen Zustand wirft respond(0) einen Fehler.
  • Kompatibilität: Chrome und Edge ab 89, Firefox ab 102, Safari erst seit 18.4. Für ältere Safari-Versionen die Funktion vorher prüfen, etwa mit typeof ReadableStreamBYOBRequest !== "undefined". In Node.js über stream/web oder global verfügbar.