Start · Sprachen · JavaScript · Referenz · ReadableStreamDefaultController.desiredSize

ReadableStreamDefaultController.desiredSize

Eigenschaft

Liefert, wie viele Einheiten (Chunks bzw. Bytes laut Queuing-Strategie) noch in die interne Warteschlange passen, bevor der Stream Gegendruck signalisiert.

seit JavaScript Baseline: alle modernen Browser (seit 2019), Node. Kategorie: webapi

Signatur

get ReadableStreamDefaultController.prototype.desiredSize

Beschreibung

Die schreibgeschützte Eigenschaft desiredSize berechnet sich aus highWaterMark minus der aktuellen Warteschlangengröße. Sie ist das zentrale Werkzeug für Gegendruck (engl. backpressure) in einer Push-Quelle: Eine Datenquelle, die von sich aus Daten liefert (z. B. WebSocket, Sensor, Timer), sollte pausieren, sobald der Wert 0 oder negativ wird, und fortfahren, wenn der Konsument wieder Platz geschaffen hat.

Wie die Größe gemessen wird, bestimmt die Queuing-Strategie im Konstruktor von ReadableStream: Bei CountQueuingStrategy (Standard, highWaterMark: 1) zählt jeder Chunk als 1, bei ByteLengthQueuingStrategy zählt die Byte-Länge der Chunks, bei einer eigenen size()-Funktion deren Rückgabewert.

Mögliche Werte:

  • positive Zahl – so viel Platz ist noch frei; der Stream möchte mehr Daten.
  • 0 oder negativ – die Warteschlange ist voll bzw. überfüllt; die Quelle sollte pausieren.
  • null – der Stream ist fehlerhaft (errored).
  • 0 – auch, wenn der Stream bereits geschlossen ist.

Bei Pull-Quellen ist ein manuelles Prüfen meist unnötig, da der Stream pull() automatisch nur dann aufruft, wenn desiredSize > 0 ist.

Rückgabewert

Typ
number | null
Beschreibung
Die verbleibende Kapazität der internen Warteschlange (highWaterMark minus aktuelle Größe). Kann negativ sein. null, wenn der Stream fehlerhaft ist; 0, wenn er geschlossen ist.

Beispiele

Wert in Abhängigkeit von der Warteschlange beobachten

const stream = new ReadableStream(
  {
    start(controller) {
      console.log('Start:', controller.desiredSize);
      controller.enqueue('a');
      console.log('Nach 1 Chunk:', controller.desiredSize);
      controller.enqueue('b');
      controller.enqueue('c');
      console.log('Nach 3 Chunks:', controller.desiredSize);
      controller.enqueue('d');
      console.log('Überfüllt:', controller.desiredSize);
    }
  },
  new CountQueuingStrategy({ highWaterMark: 3 })
);
Start: 3 Nach 1 Chunk: 2 Nach 3 Chunks: 0 Überfüllt: -1

Push-Quelle mit Gegendruck (Timer pausieren/fortsetzen)

let counter = 0;
let timer = null;

const stream = new ReadableStream(
  {
    start(controller) {
      const produce = () => {
        timer = setInterval(() => {
          controller.enqueue(`Messwert ${++counter}`);
          // Warteschlange voll -> Quelle pausieren
          if (controller.desiredSize <= 0) {
            clearInterval(timer);
            timer = null;
          }
        }, 50);
      };
      controller.produceAgain = produce;
      produce();
    },
    pull(controller) {
      // Wird aufgerufen, wenn wieder Platz ist -> fortsetzen
      if (!timer && counter < 10) controller.produceAgain();
      if (counter >= 10) controller.close();
    },
    cancel() {
      clearInterval(timer);
    }
  },
  { highWaterMark: 2 }
);

const reader = stream.getReader();
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  console.log(value);
  await new Promise((r) => setTimeout(r, 200)); // langsamer Konsument
}
Messwert 1 Messwert 2 … Messwert 10

Byte-basierte Strategie und Verhalten bei Fehler/Schließen

let ctrl;
const stream = new ReadableStream(
  { start(c) { ctrl = c; } },
  new ByteLengthQueuingStrategy({ highWaterMark: 1024 })
);

ctrl.enqueue(new Uint8Array(300));
console.log(ctrl.desiredSize); // 1024 - 300

ctrl.close();
console.log(ctrl.desiredSize); // geschlossen

const s2 = new ReadableStream({ start(c) { c.error(new Error('kaputt')); ctrl = c; } });
console.log(ctrl.desiredSize); // fehlerhaft
724 0 null

// Wichtig · Fallstricke

  • Negative Werte sind erlaubt: enqueue() blockiert nie und wirft auch bei voller Warteschlange keinen Fehler. Gegendruck ist rein kooperativ – wer desiredSize ignoriert, riskiert unbegrenzt wachsenden Speicherverbrauch.
  • null prüfen: Ein Vergleich wie desiredSize <= 0 ergibt bei null true (da null zu 0 konvertiert wird) – das ist meist gewollt, aber für eine gezielte Fehlerbehandlung explizit === null prüfen.
  • Nach close() ist der Wert 0, obwohl noch ungelesene Chunks in der Warteschlange liegen können.
  • Bei Byte-Streams (type: "bytes") erhält man stattdessen einen ReadableByteStreamController, der eine gleichnamige Eigenschaft mit Byte-Semantik besitzt.
  • Kompatibilität: In allen aktuellen Browsern (Chrome, Edge, Firefox 65+, Safari) sowie in Node.js (global ab v18, über node:stream/web ab v16.5) und Deno verfügbar; auch in Web Workern.