Signatur
Beschreibung
Der Konstruktor WebSocketStream() öffnet eine WebSocket-Verbindung zur angegebenen URL. Anders als beim klassischen WebSocket gibt es keine Ereignisse wie onmessage: Die Verbindung wird über Promises und die Streams API gesteuert. Sobald der Handshake geklappt hat, löst sich das Promise opened mit einem Objekt auf, das einen readable- und einen writable-Stream enthält.
Der große Vorteil ist der Gegendruck (engl. backpressure): Liest die Anwendung langsamer, als Nachrichten ankommen, puffert der Browser nicht unbegrenzt, sondern bremst das Lesen vom Socket. Beim Schreiben wartet await writer.write(), bis die Daten tatsächlich weitergegeben werden können. Das hilft bei großen Datenmengen oder langsamen Geräten und verhindert, dass der Speicher voll läuft.
Über options.protocols können Unterprotokolle ausgehandelt werden, über options.signal lässt sich der Verbindungsaufbau mit einem AbortController abbrechen (zum Beispiel für einen Timeout). Die Verbindung schließt man mit close({ closeCode, reason }); das Promise closed meldet, wann und warum sie beendet wurde.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $url Pflicht | string | URL | URL des WebSocket-Servers. Erlaubt sind die Schemata ws: und wss:. Relative URLs sowie http:/https: werden in modernen Implementierungen passend umgewandelt. |
|
| $options | object | {} | Optionales Konfigurationsobjekt mit den folgenden Eigenschaften. |
| $options.protocols | string[] | [] | Liste der gewünschten Unterprotokolle, z. B. ['chat.v2', 'chat.v1']. Welches der Server gewählt hat, steht nach dem Öffnen in protocol. |
| $options.signal | AbortSignal | Signal, mit dem sich der Verbindungsaufbau abbrechen lässt. Wird es vor dem Öffnen ausgelöst, werden opened und closed abgelehnt. Nach dem Handshake hat das Signal keine Wirkung mehr. |
Rückgabewert
WebSocketStream-Instanz mit den Eigenschaften url, opened (Promise<{ readable, writable, protocol, extensions }>) und closed (Promise<{ closeCode, reason }>) sowie der Methode close().Beispiele
Verbindung öffnen, senden und Nachrichten lesen
const wss = new WebSocketStream('wss://echo.example.com/');
const { readable, writable, protocol } = await wss.opened;
console.log('Verbunden, Protokoll:', protocol || '(keins)');
const writer = writable.getWriter();
const reader = readable.getReader();
// Nachricht senden – await berücksichtigt den Gegendruck
await writer.write('Hallo Server!');
// Antworten lesen, bis der Server die Verbindung schließt
while (true) {
const { value, done } = await reader.read();
if (done) break;
console.log('Empfangen:', value);
}
Verbindungsaufbau mit Timeout über AbortSignal
const connect = async (url, timeoutMs = 5000) => {
const wss = new WebSocketStream(url, {
protocols: ['chat.v2', 'chat.v1'],
signal: AbortSignal.timeout(timeoutMs)
});
try {
const connection = await wss.opened;
console.log('Ausgehandeltes Protokoll:', connection.protocol);
return { wss, ...connection };
} catch (err) {
console.error('Verbindung fehlgeschlagen:', err.name);
throw err;
}
};
const { wss } = await connect('wss://chat.example.com/socket');
Eingehende Daten per pipeTo weiterverarbeiten und sauber schließen
const wss = new WebSocketStream('wss://ticker.example.com/prices');
const { readable } = await wss.opened;
// Jede Nachricht als JSON parsen und ausgeben
const logger = new WritableStream({
write(chunk) {
const { symbol, price } = JSON.parse(chunk);
console.log(`${symbol}: ${price}`);
}
});
readable.pipeTo(logger).catch(() => {});
// Nach 10 Sekunden ordentlich beenden
setTimeout(() => wss.close({ closeCode: 1000, reason: 'Fertig' }), 10_000);
const { closeCode, reason } = await wss.closed;
console.log('Geschlossen:', closeCode, reason);
Funktionsprüfung mit Rückfall auf WebSocket
const supportsStreams = 'WebSocketStream' in globalThis;
if (supportsStreams) {
const wss = new WebSocketStream('wss://example.com/live');
const { writable } = await wss.opened;
const writer = writable.getWriter();
await writer.write(new Uint8Array([1, 2, 3]));
} else {
const ws = new WebSocket('wss://example.com/live');
ws.binaryType = 'arraybuffer';
ws.addEventListener('open', () => ws.send(new Uint8Array([1, 2, 3])));
}
console.log('WebSocketStream verfügbar:', supportsStreams);
// Wichtig · Fallstricke
- Experimentell und nicht standardisiert: Derzeit nur in Chromium-Browsern (ab Version 124) verfügbar, nicht in Firefox und Safari. Immer mit
'WebSocketStream' in globalThisprüfen und aufWebSocketzurückfallen. - Eine ungültige URL oder ein nicht unterstütztes Schema (z. B.
ftp:) oder eine URL mit Fragment (#…) löst sofort einenSyntaxErroraus. Doppelte oder ungültige Einträge inprotocolsführen ebenfalls zu einemSyntaxError. - Netzwerk- oder Handshake-Fehler werfen keine Ausnahme im Konstruktor, sondern führen zur Ablehnung von
openedundclosed. Fange beide ab, sonst gibt es Warnungen wegen nicht behandelter Promise-Ablehnungen. - Textnachrichten kommen als
stringan, Binärnachrichten alsUint8Array(nicht alsBlob). Geschrieben werden dürfen Strings,ArrayBufferundArrayBufferView. - Auf HTTPS-Seiten muss
wss:verwendet werden (Mixed Content). Der Server sollte denOrigin-Header prüfen, weil WebSockets nicht der Same-Origin-Policy/CORS unterliegen. - Gültige
closeCode-Werte fürclose()sind1000und3000–4999;reasondarf höchstens 123 Byte (UTF-8) lang sein.