gotchatypescriptMajor
WebSocket Connection State Must Be Tracked Locally Due to Delayed readyState Updates
Viewed 0 times
websocketreadyStateconnection statemessage queuedisconnectreconnectreliable send
Problem
Code checks ws.readyState === WebSocket.OPEN before sending but messages are still lost. The readyState can show OPEN briefly after the connection drops before the browser detects the failure.
Solution
Maintain a local connected flag updated only in the onopen and onclose/onerror handlers. Gate all sends on this flag and enqueue messages when disconnected.
class ReliableWebSocket {
private ws: WebSocket | null = null;
private connected = false;
private queue: string[] = [];
connect(url: string) {
this.ws = new WebSocket(url);
this.ws.onopen = () => {
this.connected = true;
this.flush();
};
this.ws.onclose = () => { this.connected = false; };
this.ws.onerror = () => { this.connected = false; };
}
send(data: unknown) {
const msg = JSON.stringify(data);
if (this.connected && this.ws) {
this.ws.send(msg);
} else {
this.queue.push(msg);
}
}
private flush() {
while (this.queue.length && this.connected) {
this.ws!.send(this.queue.shift()!);
}
}
}Why
WebSocket readyState is a browser-managed value that lags behind actual network state by up to the TCP keepalive interval. A network partition can leave readyState as OPEN for 30–90 seconds.
Gotchas
- Queue size must be bounded — an unbounded queue during a long disconnect will exhaust memory.
- Messages sent from the queue on reconnect may arrive out of order relative to messages sent by others.
- Add a sequence number to messages so the server can detect and reject duplicates on reconnect.
- The browser fires onerror then onclose — always handle both; don't rely on just onclose.
Revisions (0)
No revisions yet.