Start · Sprachen · JavaScript · Referenz · ReadableByteStreamController.byobRequest

ReadableByteStreamController.byobRequest

Eigenschaft

Gibt die aktuell ausstehende BYOB-Leseanfrage als <code>ReadableStreamBYOBRequest</code> zurück oder <code>null</code>, wenn keine Anfrage offen ist.

seit JavaScript Baseline 2024 (Chrome 89, Firefox 102, Safari 16.4 Kategorie: webapi

Signatur

get ReadableByteStreamController.prototype.byobRequest

Beschreibung

Die schreibgeschützte Eigenschaft byobRequest gehört zum ReadableByteStreamController, also dem Controller eines Byte-Streams (new ReadableStream({ type: "bytes", ... })). Liest ein Konsument den Stream mit einem ReadableStreamBYOBReader („Bring Your Own Buffer“), stellt er einen eigenen Puffer bereit. Über controller.byobRequest kommt die Quelle direkt an diesen Puffer (byobRequest.view) und kann die Daten ohne Zwischenkopie hineinschreiben.

Typischerweise fragt man die Eigenschaft in der pull()-Methode der zugrunde liegenden Quelle ab. Gibt es eine Anfrage, schreibt man bis zu view.byteLength Bytes in view und bestätigt dann mit byobRequest.respond(bytesWritten). Ist sie null, stellt man die Daten wie gewohnt mit controller.enqueue() bereit.

Wenn die Quelle mit autoAllocateChunkSize angelegt wurde, erzeugt der Stream auch für normale Leser (getReader() ohne mode: "byob") automatisch einen Puffer dieser Größe. Dann ist byobRequest in pull() immer gesetzt, und die Quelle braucht nur einen einzigen Codepfad.

Rückgabewert

Typ
ReadableStreamBYOBRequest | null
Beschreibung
Ein ReadableStreamBYOBRequest mit der Eigenschaft view (ein Uint8Array bzw. ArrayBufferView, in den geschrieben wird) sowie den Methoden respond() und respondWithNewView(). Gibt null zurück, wenn keine BYOB-Anfrage offen ist.

Beispiele

Zufallsbytes direkt in den Puffer des Lesers schreiben

const stream = new ReadableStream({
  type: "bytes",
  pull(controller) {
    const request = controller.byobRequest;
    if (request) {
      // Direkt in den vom Leser bereitgestellten Puffer schreiben
      const view = request.view;
      crypto.getRandomValues(view);
      request.respond(view.byteLength);
    } else {
      // Rückfall für Standard-Leser
      controller.enqueue(crypto.getRandomValues(new Uint8Array(16)));
    }
  }
});

const reader = stream.getReader({ mode: "byob" });
const { value } = await reader.read(new Uint8Array(8));
console.log(value.byteLength);
8

Mit autoAllocateChunkSize nur einen Codepfad nutzen

const data = new TextEncoder().encode("Hallo, Byte-Stream!");
let offset = 0;

const stream = new ReadableStream({
  type: "bytes",
  autoAllocateChunkSize: 4,
  pull(controller) {
    // Wegen autoAllocateChunkSize ist byobRequest hier nie null
    const { view } = controller.byobRequest;
    const chunk = data.subarray(offset, offset + view.byteLength);
    view.set(chunk);
    offset += chunk.byteLength;
    controller.byobRequest.respond(chunk.byteLength);
    if (offset >= data.byteLength) {
      controller.close();
    }
  }
});

// Auch ein normaler Leser funktioniert
const reader = stream.getReader();
const parts = [];
for (;;) {
  const { done, value } = await reader.read();
  if (done) break;
  parts.push(value.byteLength);
}
console.log(parts);
[4, 4, 4, 4, 3]

Prüfen, ob eine Anfrage offen ist

let ctrl;
const stream = new ReadableStream({
  type: "bytes",
  start(controller) {
    ctrl = controller;
  }
});

console.log(ctrl.byobRequest); // noch kein Lesevorgang

const reader = stream.getReader({ mode: "byob" });
const pending = reader.read(new Uint8Array(10));
console.log(ctrl.byobRequest.view.byteLength);

ctrl.byobRequest.view.set([1, 2, 3]);
ctrl.byobRequest.respond(3);
console.log((await pending).value);
null 10 Uint8Array(3) [1, 2, 3]

// Wichtig · Fallstricke

  • Nur bei Byte-Streams: Die Eigenschaft gibt es nur, wenn der Stream mit type: "bytes" angelegt wurde. Bei normalen Streams ist der Controller ein ReadableStreamDefaultController, und der hat kein byobRequest.
  • Immer beantworten: Nach dem Schreiben in view muss respond(n) oder respondWithNewView(view) aufgerufen werden. Sonst bleibt das read()-Promise des Lesers offen.
  • Übertragene Puffer: Nach respond() ist die Anfrage erledigt und der alte view-Puffer übertragen (detached). Später darauf zuzugreifen ist ein Fehler. Deshalb die Eigenschaft bei jedem pull() neu abfragen und keine Referenz zwischenspeichern.
  • Nach dem Schließen: Ist der Stream geschlossen, muss respond(0) aufgerufen werden, um eine offene Anfrage abzuschließen. Ein Wert größer als 0 löst dann einen TypeError aus.
  • Kompatibilität: Safari unterstützt Byte-Streams und BYOB-Leser erst ab Version 16.4, Firefox ab Version 102. Bei älteren Browsern vorher prüfen, ob ReadableStreamBYOBReader existiert (Feature-Erkennung).