Start · Sprachen · JavaScript · Referenz · ByteLengthQueuingStrategy

ByteLengthQueuingStrategy

Schnittstelle

Eingebaute Warteschlangenstrategie der Streams API, die die Größe jedes Chunks über seine <code>byteLength</code> misst und so Gegendruck (Backpressure) in Bytes steuert.

seit JavaScript Baseline: alle modernen Browser (seit 2022 durchgä Kategorie: webapi

Signatur

interface ByteLengthQueuingStrategy

Beschreibung

ByteLengthQueuingStrategy ist eine fertige Warteschlangenstrategie, die man als zweites Argument an new ReadableStream(), new WritableStream() oder als Strategie für TransformStream übergibt. Sie legt fest, wie viele Daten ein Stream intern puffern darf, bevor er Gegendruck meldet. Gemessen wird dabei nicht in Chunks, sondern in Bytes: Die Größe jedes Chunks ergibt sich aus dessen Eigenschaft byteLength.

Das ist sinnvoll, wenn deine Chunks binäre Daten sind, also ArrayBuffer, Uint8Array oder andere TypedArrays bzw. DataViews. Chunks können unterschiedlich groß sein. Mit einer Byte-Grenze bleibt der Speicherverbrauch trotzdem vorhersagbar, zum Beispiel „höchstens 64 KiB puffern“.

Die Instanz hat zwei nur lesbare Eigenschaften:

  • highWaterMark: die im Konstruktor angegebene Obergrenze in Bytes.
  • size(chunk): eine Funktion, die chunk.byteLength zurückgibt.

Der Stream vergleicht die Summe aller gepufferten Größen mit highWaterMark. Wird die Grenze erreicht, sinkt controller.desiredSize bzw. writer.desiredSize auf 0 oder darunter. Außerdem ruft ein ReadableStream dann pull() nicht mehr auf, und writer.ready bleibt ausstehend. Für Streams mit beliebigen JavaScript-Werten ist stattdessen CountQueuingStrategy passend.

Parameter

Name Typ Default Beschreibung
$options Pflicht { highWaterMark: number } Konfigurationsobjekt. Das Feld highWaterMark ist Pflicht. Fehlt es, wirft der Konstruktor einen TypeError.
$options.highWaterMark Pflicht number Gesamtzahl an Bytes, die der Stream puffern darf, bevor Gegendruck ausgelöst wird. Nicht-negative Zahl; 0 bedeutet: nichts im Voraus puffern.

Rückgabewert

Typ
ByteLengthQueuingStrategy
Beschreibung
Eine neue Strategie-Instanz mit den Eigenschaften highWaterMark (number) und size(chunk) (liefert chunk.byteLength).

Beispiele

Instanziierung und Eigenschaften

const strategy = new ByteLengthQueuingStrategy({ highWaterMark: 16 * 1024 });

console.log(strategy.highWaterMark);
console.log(strategy.size(new Uint8Array(512)));
console.log(strategy.size(new ArrayBuffer(2048)));
16384 512 2048

ReadableStream mit Byte-Grenze beim Erzeugen von Zufallsdaten

let produced = 0;
const stream = new ReadableStream({
  pull(controller) {
    // Nur aufgerufen, solange weniger als 8 KiB gepuffert sind
    const chunk = crypto.getRandomValues(new Uint8Array(1024));
    controller.enqueue(chunk);
    produced += chunk.byteLength;
    console.log(`erzeugt: ${produced}, desiredSize: ${controller.desiredSize}`);
    if (produced >= 4096) controller.close();
  }
}, new ByteLengthQueuingStrategy({ highWaterMark: 8 * 1024 }));

const reader = stream.getReader();
let total = 0;
for (;;) {
  const { done, value } = await reader.read();
  if (done) break;
  total += value.byteLength;
}
console.log('gelesen:', total);
erzeugt: 1024, desiredSize: 7168 erzeugt: 2048, desiredSize: 6144 erzeugt: 3072, desiredSize: 5120 erzeugt: 4096, desiredSize: 4096 gelesen: 4096

WritableStream mit Gegendruck: auf writer.ready warten

const sink = new WritableStream({
  async write(chunk) {
    // Langsames Ziel simulieren, z. B. Upload oder Festplatte
    await new Promise((r) => setTimeout(r, 50));
    console.log('geschrieben:', chunk.byteLength, 'Bytes');
  }
}, new ByteLengthQueuingStrategy({ highWaterMark: 4096 }));

const writer = sink.getWriter();
for (let i = 0; i < 4; i++) {
  await writer.ready; // blockiert, wenn mehr als 4 KiB gepuffert sind
  writer.write(new Uint8Array(3000));
  console.log('desiredSize:', writer.desiredSize);
}
await writer.close();
desiredSize: 1096 desiredSize: -1904 geschrieben: 3000 Bytes ...

// Wichtig · Fallstricke

  • Nur für binäre Chunks: Die Funktion size() liest chunk.byteLength. Strings haben diese Eigenschaft nicht. Die Größe ist dann undefined, und enqueue() bzw. write() scheitern mit einem RangeError. Strings solltest du vorher mit TextEncoder umwandeln oder CountQueuingStrategy verwenden.
  • Keine eigenen Byte-Streams: Bei new ReadableStream({ type: 'bytes' }) darf keine size-Funktion übergeben werden. Übergib dort nur { highWaterMark } als einfaches Objekt, sonst wird ein RangeError geworfen.
  • highWaterMark ist eine Empfehlung, keine harte Grenze. enqueue() und write() nehmen auch bei negativer desiredSize weitere Chunks an. Gegendruck wirkt nur, wenn Quelle oder Schreiber desiredSize bzw. writer.ready tatsächlich beachten.
  • Statt einer Instanz kannst du auch ein eigenes Objekt { highWaterMark, size(chunk) { … } } übergeben. Die eingebaute Klasse ist aber klarer und wird von der Laufzeitumgebung besser optimiert.
  • Kompatibilität: Wird in Chrome, Edge, Firefox und Safari unterstützt, außerdem in Web Workers. In Node.js ist die Klasse ab Version 18 global verfügbar, davor über require('node:stream/web').