Start · Sprachen · JavaScript · Referenz · ReadableStreamBYOBRequest.respondWithNewView()

ReadableStreamBYOBRequest.respondWithNewView()

Methode

Beantwortet eine BYOB-Leseanforderung mit einer neuen <code>ArrayBufferView</code> auf den (übertragenen) Puffer und meldet damit, wie viele Bytes geschrieben wurden.

seit JavaScript Streams-Standard; Chromium 89+, Firefox 102+, Safa Kategorie: webapi

Signatur

ReadableStreamBYOBRequest.prototype.respondWithNewView(view)

Beschreibung

respondWithNewView() wird in der Datenquelle eines lesbaren Bytestreams (new ReadableStream({ type: "bytes" })) verwendet. Die Methode beantwortet die aktuelle BYOB-Anforderung („bring your own buffer“). Anders als bei respond(bytesWritten) übergibt man dabei nicht einfach eine Anzahl von Bytes, sondern eine neue Ansicht (ArrayBufferView). Ihre byteLength gibt an, wie viele Bytes geschrieben wurden.

Das braucht man vor allem, wenn der ursprüngliche ArrayBuffer aus byobRequest.view während des Füllens übertragen wurde, also losgelöst („detached“) ist. Das passiert zum Beispiel mit ArrayBuffer.prototype.transfer(), mit structuredClone(…, { transfer }) oder mit postMessage an einen Worker. Die alte view ist danach unbrauchbar. Deshalb baut man auf dem zurückerhaltenen Puffer eine neue Ansicht und reicht sie mit respondWithNewView() weiter.

Für die neue Ansicht gelten strenge Regeln:

  • Sie muss denselben byteOffset haben wie die ursprüngliche view.
  • Der zugrunde liegende Puffer muss dieselbe Gesamtlänge (buffer.byteLength) haben wie der ursprüngliche Puffer.
  • Ihre byteLength darf nicht größer sein als die ursprüngliche view.byteLength.
  • Wurde der Stream bereits geschlossen, muss die byteLength genau 0 sein.

Nach dem Aufruf ist die Anforderung erledigt. controller.byobRequest ist dann null oder verweist auf eine neue Anforderung.

Parameter

Name Typ Default Beschreibung
$view Pflicht ArrayBufferView (z. B. Uint8Array, DataView) Neue Ansicht auf den (ggf. übertragenen) Puffer mit den geschriebenen Daten. Der byteOffset muss dem der ursprünglichen byobRequest.view entsprechen. Die byteLength ist die Anzahl der geschriebenen Bytes.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Der wartende read()-Aufruf des BYOB-Readers wird mit einer Ansicht auf die geschriebenen Bytes erfüllt.

Beispiele

Puffer mit transfer() übernehmen und beantworten

const stream = new ReadableStream({
  type: "bytes",
  pull(controller) {
    const req = controller.byobRequest;
    const { buffer, byteOffset, byteLength } = req.view;

    // Puffer übernehmen – die alte req.view ist danach losgelöst
    const owned = buffer.transfer();
    const bytes = new Uint8Array(owned, byteOffset, byteLength);

    const n = Math.min(4, byteLength);
    for (let i = 0; i < n; i++) bytes[i] = 65 + i; // 'A'..'D'

    // Neue Ansicht: gleicher Offset, Länge = geschriebene Bytes
    req.respondWithNewView(new Uint8Array(owned, byteOffset, n));
  }
});

const reader = stream.getReader({ mode: "byob" });
const { value, done } = await reader.read(new Uint8Array(8));
console.log(Array.from(value), done);
[65, 66, 67, 68] false

Asynchrones Füllen mit Transfer (Worker-Muster simuliert)

// Simuliert z. B. einen Worker: Puffer hin übertragen, gefüllt zurückbekommen
const fillElsewhere = async (buffer, offset, length) => {
  const moved = structuredClone(buffer, { transfer: [buffer] });
  const view = new Uint8Array(moved, offset, length);
  const text = new TextEncoder().encode("Hallo");
  const n = Math.min(text.length, length);
  view.set(text.subarray(0, n));
  return { buffer: moved, written: n };
};

let sent = false;
const stream = new ReadableStream({
  type: "bytes",
  async pull(controller) {
    const req = controller.byobRequest;
    const { buffer, byteOffset, byteLength } = req.view;

    if (sent) {
      controller.close();
      // Nach close() muss mit einer Ansicht der Länge 0 geantwortet werden
      req.respondWithNewView(new Uint8Array(buffer, byteOffset, 0));
      return;
    }

    const result = await fillElsewhere(buffer, byteOffset, byteLength);
    req.respondWithNewView(new Uint8Array(result.buffer, byteOffset, result.written));
    sent = true;
  }
});

const reader = stream.getReader({ mode: "byob" });
let r = await reader.read(new Uint8Array(16));
console.log(new TextDecoder().decode(r.value));
r = await reader.read(new Uint8Array(16));
console.log(r.done);
Hallo true

Typischer Fehler: falscher byteOffset

const stream = new ReadableStream({
  type: "bytes",
  pull(controller) {
    const req = controller.byobRequest;
    const { buffer, byteOffset } = req.view;
    try {
      // Offset weicht ab → RangeError
      req.respondWithNewView(new Uint8Array(buffer, byteOffset + 1, 1));
    } catch (err) {
      console.log(err.name);
      controller.error(err);
    }
  }
});

const reader = stream.getReader({ mode: "byob" });
reader.read(new Uint8Array(8)).catch(() => {});
RangeError