Start · Sprachen · JavaScript · Referenz · WebTransportDatagramDuplexStream.writable

WebTransportDatagramDuplexStream.writable

Eigenschaft

Schreibgeschützte Eigenschaft, die einen <code>WritableStream</code> liefert, über den man ausgehende Datagramme unzuverlässig über eine WebTransport-Verbindung sendet.

seit JavaScript Chrome/Edge 97+, Firefox 114+; Safari erst in neue deprecated seit ja Kategorie: webapi

Signatur

WebTransportDatagramDuplexStream.writable

Beschreibung

Die Eigenschaft writable eines WebTransportDatagramDuplexStream (erreichbar über transport.datagrams) gibt einen WritableStream zurück. Jeder Chunk, den du hineinschreibst, wird als einzelnes Datagramm über HTTP/3 bzw. QUIC an den Server geschickt. Chunks müssen BufferSource-Werte sein, typischerweise Uint8Array.

Datagramme sind unzuverlässig und ungeordnet: Sie können verloren gehen, doppelt oder in anderer Reihenfolge ankommen. Dafür gibt es kein Head-of-Line-Blocking und die Latenz ist sehr gering. Das passt gut für Daten, bei denen nur der neueste Stand zählt, etwa Spielerpositionen in Multiplayer-Spielen, Sensordaten, Echtzeit-Telemetrie oder Cursor-Positionen. Wenn die Daten sicher und in der richtigen Reihenfolge ankommen müssen, verwende stattdessen unidirektionale oder bidirektionale Streams (createUnidirectionalStream(), createBidirectionalStream()).

Zum Schreiben holst du dir mit getWriter() einen WritableStreamDefaultWriter und rufst write() auf. Das zurückgegebene Promise wird erfüllt, sobald das Datagramm zum Senden eingereiht ist. Das heißt aber nicht, dass es angekommen ist. Die maximale Nutzlast pro Datagramm steht in datagrams.maxDatagramSize. Mit outgoingHighWaterMark und outgoingMaxAge steuerst du die Pufferung und wie lange ausgehende Datagramme in der Warteschlange bleiben dürfen, bevor sie verworfen werden.

Rückgabewert

Typ
WritableStream<BufferSource>
Beschreibung
Ein WritableStream, dessen Chunks jeweils als ein Datagramm gesendet werden. Pro Duplex-Stream wird immer dieselbe Instanz zurückgegeben.

Beispiele

Einfaches Datagramm senden

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

const writer = transport.datagrams.writable.getWriter();
const data = new TextEncoder().encode('Hallo Server');

await writer.write(data); // nur eingereiht, nicht bestätigt
console.log('Datagramm eingereiht, Größe:', data.byteLength);

writer.releaseLock();
Datagramm eingereiht, Größe: 11

Spielerposition mit Größenprüfung senden

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

const { datagrams } = transport;
const writer = datagrams.writable.getWriter();

const sendPosition = async (x, y) => {
  const buffer = new Float32Array([x, y]);
  const bytes = new Uint8Array(buffer.buffer);
  if (bytes.byteLength > datagrams.maxDatagramSize) {
    console.warn('Datagramm zu groß – wird nicht gesendet');
    return;
  }
  await writer.ready; // Gegendruck beachten
  writer.write(bytes).catch((err) => console.error('Senden fehlgeschlagen:', err));
};

// 20-mal pro Sekunde die aktuelle Position senden
let x = 0;
const timer = setInterval(() => sendPosition(x++, 42), 50);

transport.closed.finally(() => clearInterval(timer));

Warteschlange konfigurieren und sauber schließen

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

// veraltete Messwerte nach 200 ms verwerfen
transport.datagrams.outgoingMaxAge = 200;
transport.datagrams.outgoingHighWaterMark = 10;

const writer = transport.datagrams.writable.getWriter();
const encoder = new TextEncoder();

for (const value of [21.3, 21.4, 21.6]) {
  await writer.write(encoder.encode(JSON.stringify({ temp: value, t: Date.now() })));
}

writer.releaseLock();
transport.close({ closeCode: 0, reason: 'Fertig' });
console.log('Verbindung geschlossen');
Verbindung geschlossen

// Wichtig · Fallstricke

  • Keine Zustellgarantie: Ein erfülltes write()-Promise bedeutet nur, dass das Datagramm eingereiht wurde. Datagramme können verloren gehen oder in anderer Reihenfolge ankommen. Wenn nötig, musst du Bestätigungen oder Sequenznummern selbst umsetzen.
  • Größenlimit: Datagramme, die größer als maxDatagramSize sind, werden verworfen. Je nach Implementierung passiert das still oder mit einem Fehler. Deshalb die Größe vorher prüfen. Der Wert kann sich im Lauf der Verbindung ändern (Path-MTU).
  • Sperre: Solange ein Writer aktiv ist, ist der Stream gesperrt (locked === true). Ein zweiter Aufruf von getWriter() wirft einen TypeError. Gib den Writer deshalb mit releaseLock() frei.
  • Chunk-Typ: Es werden nur ArrayBuffer bzw. ArrayBufferView akzeptiert. Strings musst du vorher mit TextEncoder umwandeln.
  • Spezifikation im Wandel: Neuere Entwürfe der WebTransport-Spezifikation führen datagrams.createWritable(options) ein, etwa für Prioritäten oder Sendegruppen. Das Attribut writable gilt dort als veraltet. Prüfe vor dem Einsatz, was deine Zielbrowser unterstützen.
  • Kompatibilität: Funktioniert nur in sicheren Kontexten (HTTPS) und braucht einen Server mit HTTP/3-Unterstützung. Unterstützt wird es von Chromium-Browsern ab Version 97 und Firefox ab 114. In Safari kam die Unterstützung erst spät. Mit 'WebTransport' in globalThis prüfen, ob die API vorhanden ist, und bei Bedarf auf WebSocket zurückfallen.