readyState is your guard
Calling ws.send() on a connection that is not OPEN throws a InvalidStateError. The fix is not "wrap in try/catch" — it is "check readyState first, or queue the message until open fires." Treat readyState as the source of truth for "can I send right now?"
The four values
0 CONNECTING — handshake in flight. 1 OPEN — frames flow. 2 CLOSING — close handshake started. 3 CLOSED — terminal. The WebSocket.OPEN static constant lets you write ws.readyState === WebSocket.OPEN and skip the magic numbers.