websocket连接后立即send失败因状态延迟,需safeSend校验readyState;心跳需应用层实现ping/pong;onmessage应try-catch、防阻塞、区分数据类型;重连须指数退避并清理旧连接。

WebSocket 连接建立后立即收发消息失败?
常见现象是 onopen 触发了,但紧接着 send() 报错 InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state。这是因为连接状态切换有微小延迟,onopen 回调虽已触发,底层握手未必完全就绪。
- 稳妥做法:在
onopen回调里用setTimeout(() => ws.send(...), 0)或直接用ws.readyState === WebSocket.OPEN双重校验 - 更推荐封装一个
safeSend()方法,内部轮询或 promise 化等待就绪 - 不要依赖
onopen后立刻发包——浏览器实现和网络抖动会让这个“立刻”不可靠
如何处理心跳与自动重连?
WebSocket 没有内置心跳机制,服务端通常会在空闲 30–60 秒后关闭连接。客户端不主动探测,就会静默断开,且 onclose 不一定及时触发。
- 服务端若支持
Ping/Pong帧,浏览器会自动响应,但多数 node.js/python 后端需手动实现;更通用的做法是应用层心跳 - 定时用
ws.send(jsON.stringify({ type: 'ping' })),并监听对应pong响应(服务端返回{ type: 'pong' }) - 重连逻辑必须限制次数和间隔,例如指数退避:
1s → 2s → 4s → 8s,超过 5 次失败后暂停或提示用户 - 重连前要清除旧定时器、置空
ws引用,否则可能产生多个并发连接
接收消息时如何区分业务类型并避免阻塞主线程?
onmessage 是同步回调,如果解析大 json 或执行复杂逻辑,会卡住 ui。同时,服务端可能批量推送、乱序到达,纯靠 JSON.parse() 容易崩溃。
- 始终用
try...catch包裹JSON.parse(),并记录原始Event.data便于排查 - 对高频消息(如实时位置、传感器数据),考虑用
requestIdleCallback()或setTimeout(..., 0)延迟处理,让出主线程 - 用
event.data instanceof Blob判断是否为二进制数据,避免误转字符串;必要时用new FileReader().readAsText() - 不要在
onmessage里直接更新大量 dom,优先写入内存缓存,再节流渲染
const ws = new WebSocket('wss://api.example.com'); ws.onmessage = (event) => { try { const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data; if (data.type === 'chat') { handleChat(data.payload); } else if (data.type === 'ping') { ws.send(JSON.stringify({ type: 'pong' })); } } catch (e) { console.error('Invalid message:', event.data, e); } };
WebSocket 的真实难点不在连接本身,而在连接之后的状态同步、错误恢复和消息生命周期管理——尤其是重连时未发完的消息如何暂存、重复投递怎么去重、离线期间的本地操作如何合并。这些没法靠一个 new WebSocket() 解决。