Start · Sprachen · JavaScript · Referenz · WebTransportDatagramDuplexStream.readable

WebTransportDatagramDuplexStream.readable

Eigenschaft

Schreibgeschützte Eigenschaft, die einen <code>ReadableStream</code> liefert, über den eingehende WebTransport-Datagramme unzuverlässig und ungeordnet gelesen werden.

seit JavaScript Chrome/Edge 97+, Firefox 114+, Safari: nicht unter Kategorie: webapi

Signatur

WebTransportDatagramDuplexStream.readable

Beschreibung

Die Eigenschaft readable des Interfaces WebTransportDatagramDuplexStream gibt einen ReadableStream zurück. Jeder Chunk darin ist ein Uint8Array und steht für genau ein Datagramm, das der Server geschickt hat. An das Objekt kommst du über WebTransport.datagrams.

Datagramme laufen über QUIC und sind unzuverlässig: Sie können verloren gehen, in anderer Reihenfolge ankommen oder verworfen werden, wenn die Warteschlange voll ist. Dafür gibt es keine Verzögerung durch erneutes Senden und kein Warten auf vorherige Pakete (kein Head-of-Line-Blocking). Deshalb eignen sie sich für Echtzeitdaten, bei denen nur der neueste Stand zählt, etwa Spielzustände, Sensorwerte, Positionsdaten oder Telemetrie.

So wird typischerweise gelesen: Mit readable.getReader() holst du dir einen Reader und rufst in einer Schleife read() auf, bis done gleich true ist. Alternativ verarbeitest du den Stream mit for await...of (async iteration) oder leitest ihn mit pipeThrough() / pipeTo() weiter. Wie viele eingehende Datagramme zwischengespeichert werden und wie lange sie gültig bleiben, bestimmen incomingHighWaterMark und incomingMaxAge.

Rückgabewert

Typ
ReadableStream<Uint8Array>
Beschreibung
Ein ReadableStream, dessen Chunks jeweils ein empfangenes Datagramm als Uint8Array sind. Beim Zugriff wird immer dieselbe Instanz zurückgegeben.

Beispiele

Datagramme mit einem Reader lesen

const transport = new WebTransport('https://example.com:4999/wt');
await transport.ready;

const reader = transport.datagrams.readable.getReader();
const decoder = new TextDecoder();

try {
  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    // value ist ein Uint8Array – ein Datagramm
    console.log('Empfangen:', decoder.decode(value));
  }
} catch (err) {
  console.error('Datagramm-Stream abgebrochen:', err);
} finally {
  reader.releaseLock();
}
Empfangen: {"x":12,"y":40} Empfangen: {"x":13,"y":41}

Spielzustand per for await...of verarbeiten

const transport = new WebTransport('https://game.example.com/session');
await transport.ready;

const decoder = new TextDecoder();
let latestState = null;

for await (const chunk of transport.datagrams.readable) {
  const state = JSON.parse(decoder.decode(chunk));
  // Nur neuere Zustände übernehmen – Reihenfolge ist nicht garantiert
  if (!latestState || state.tick > latestState.tick) {
    latestState = state;
    console.log('Tick', state.tick, 'Spieler:', state.players.length);
  }
}
Tick 1021 Spieler: 4 Tick 1022 Spieler: 4

Binäre Sensordaten über pipeThrough dekodieren

const transport = new WebTransport('https://iot.example.com/telemetry');
await transport.ready;

// Jedes Datagramm: 4 Byte Sensor-ID + 8 Byte Float64-Messwert
const parser = new TransformStream({
  transform(chunk, controller) {
    const view = new DataView(chunk.buffer, chunk.byteOffset, chunk.byteLength);
    controller.enqueue({ id: view.getUint32(0), value: view.getFloat64(4) });
  }
});

await transport.datagrams.readable
  .pipeThrough(parser)
  .pipeTo(new WritableStream({
    write: ({ id, value }) => console.log(`Sensor ${id}: ${value.toFixed(2)}`)
  }));
Sensor 7: 21.53 Sensor 3: 19.88

// Wichtig · Fallstricke

  • Keine Zustellgarantie: Datagramme können fehlen, doppelt oder in falscher Reihenfolge ankommen. Wenn deine Anwendung das nicht verträgt, gib Sequenznummern mit oder nimm zuverlässige Streams (createBidirectionalStream(), createUnidirectionalStream()).
  • Verworfene Datagramme: Wenn du zu langsam liest, werden Datagramme verworfen, sobald die Warteschlange über incomingHighWaterMark hinauswächst oder ein Datagramm älter als incomingMaxAge ist. Lies deshalb in einer eigenen, schnellen Schleife.
  • Sperre: Solange ein Reader aktiv ist, ist der Stream gesperrt (locked === true). Ein zweiter Aufruf von getReader() wirft dann einen TypeError. Gib die Sperre mit releaseLock() wieder frei.
  • Größenbegrenzung: Wie groß ein Datagramm höchstens sein darf, hängt von der Pfad-MTU ab (siehe maxDatagramSize). Große Nutzdaten musst du selbst aufteilen.
  • Kompatibilität: Funktioniert nur in sicheren Kontexten (HTTPS) und in Chromium ab Version 97 sowie Firefox ab 114. Safari unterstützt WebTransport noch nicht. Der Server muss HTTP/3 mit WebTransport beherrschen. Prüfe die Unterstützung mit 'WebTransport' in globalThis.
  • Wird die Verbindung geschlossen oder bricht sie ab, endet der Stream bzw. read() wird mit einem WebTransportError abgelehnt.