Signatur
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
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();
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');
// 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
maxDatagramSizesind, 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 vongetWriter()wirft einenTypeError. Gib den Writer deshalb mitreleaseLock()frei. - Chunk-Typ: Es werden nur
ArrayBufferbzw.ArrayBufferViewakzeptiert. Strings musst du vorher mitTextEncoderumwandeln. - Spezifikation im Wandel: Neuere Entwürfe der WebTransport-Spezifikation führen
datagrams.createWritable(options)ein, etwa für Prioritäten oder Sendegruppen. Das Attributwritablegilt 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 globalThisprüfen, ob die API vorhanden ist, und bei Bedarf auf WebSocket zurückfallen.