WebSocket连接后立即send失败因状态延迟,需safeSend校验readyState;心跳需应用层实现ping/pong;onmessage应try-catch、防阻塞、区分数据类型;重连须指数退避并清理旧连接。
常见现象是 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(JSO
N.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() 解决。