WebSocket client with automatic reconnection (exponential backoff), message queue, and chainable event API.
Module ws | Source packages/front/fw/src/dom/net/ws.js | Deps none | Worker-safe no
Resolve
const ws = runtime.resolve('ws');
// ws is a factory: ws(url | opts) → WsConnection
API
ws(url | opts) → WsConnection
// Direct URL (all options at their defaults)
const socket = ws('wss://example.com/socket');
// With options
const socket = ws({
url: 'wss://example.com/socket',
retry: 5, // 5 max reconnection attempts (default: 0 = no retry)
retryDelay: 1000, // base delay in ms (default: 1000)
maxDelay: 30000, // maximum delay (default: 30000)
binary: 'arraybuffer' // binary type: 'arraybuffer' (default) or 'blob'
});
| Option | Type | Default | Description |
|---|---|---|---|
url |
string |
— | WebSocket URL |
retry |
number |
0 |
Max number of reconnections (0 = none) |
retryDelay |
number |
1000 |
Base delay for backoff (ms) |
maxDelay |
number |
30000 |
Maximum delay between attempts (ms) |
binary |
string |
'arraybuffer' |
Type of received binary messages |
Events — on(event, fn) → this
socket
.on('open', (event) => console.log('connected'))
.on('message', (data, event) => console.log('received:', data))
.on('close', (event, ctx) => {
// ctx.reconnecting : boolean
// ctx.attempt : number of attempts made
// ctx.remaining : remaining attempts
console.log('closed, reconnecting:', ctx.reconnecting);
})
.on('error', (event) => console.error('error'));
off(event) → this
Removes the handler (replaced with a no-op).
send(data) → this
Sends data. If the connection is not open, messages are queued and sent on reconnection.
socket.send('Hello');
socket.send(JSON.stringify({ type: 'ping' }));
socket.send(arrayBuffer);
socket.send(new Uint8Array([1, 2, 3]));
Messages sent after a permanent close() are silently ignored.
close(code?, reason?) → void
Permanently closes the connection (cancels reconnections, clears the queue).
socket.close(1000, 'Goodbye');
socket.close(); // code 1000, empty reason
Getters
| Getter | Type | Description |
|---|---|---|
isOpen |
boolean |
true when readyState === OPEN |
readyState |
number |
Raw WebSocket state (0–3) |
bufferedAmount |
number |
Bytes pending in the native send buffer |
URL resolution
| Form | Resolution |
|---|---|
ws://... / wss://... |
Used as-is |
| Relative path | Prefixed with the page protocol (https: → wss://, http: → ws://) + current host |
Reconnection — exponential backoff with full jitter
Computed delay: random(0, min(maxDelay, retryDelay × 2^attempt))
Full jitter avoids the "thundering herd" effect (simultaneous reconnections from many clients).
Examples
Complete — subscribe + reconnect
const ws = runtime.resolve('ws');
const socket = ws({
url: 'wss://api.example.com/events',
retry: 10,
retryDelay: 500,
maxDelay: 15000
});
socket
.on('open', () => {
console.log('connected');
socket.send(JSON.stringify({ type: 'subscribe', channel: 'updates' }));
})
.on('message', (data) => {
const msg = JSON.parse(data);
handleEvent(msg);
})
.on('close', (ev, { reconnecting, attempt, remaining }) => {
if (reconnecting) {
console.log(`reconnection ${attempt}, ${remaining} remaining`);
} else {
console.log('permanently disconnected');
}
})
.on('error', (ev) => {
console.error('WebSocket error');
});
// Close cleanly on exit
window.addEventListener('beforeunload', () => socket.close(1001, 'Page closed'));
Notes
onerroris always followed byonclose— update the UI inclose.- The queue is flushed automatically on reconnection.
- The attempt counter is reset to zero after a successful connection.
See also
- ajax — HTTP requests
- processMessage — inter-thread communication