onopen触发时连接已就绪,可直接send;但需检查readyState并加try-catch防兼容问题,避免在onopen中发大量数据或执行耗时操作。

onopen 回调里直接调用 send() 就行,但得确保连接真就绪了
WebSocket 的 onopen 事件触发时,连接已建立、状态为 WebSocket.OPEN(即 readyState === 1),此时调用 send() 是安全的。不需要加延时或轮询判断。
常见错误是把初始化逻辑写在 new WebSocket() 构造之后、onopen 之外——这时 readyState 很可能还是 0(CONNECTING),send() 会直接抛 InvalidStateError。
-
onopen是唯一可靠信号:它只在握手完成、底层 TCP+HTTP/1.1 Upgrade 成功后触发 - 不要依赖
setTimeout等“猜时间”方式,不同网络下延迟差异大 - 如果服务端要求认证或协商协议,初始消息应包含对应字段(比如
{"type":"auth","token":"..."})
发送前检查 readyState 是冗余但有用的防御性写法
虽然 onopen 触发时状态必为 1,但在复杂逻辑中(比如回调被复用、或封装成类),手动检查能避免误调用。尤其当代码被多人维护或后期加入重连逻辑时,这行判断成本极低,却能提前暴露问题。
ws.onopen = function() {
console.log('Connected');
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'init', version: '1.2' }));
}
};
- 即使不加判断也能跑通,但加上后调试时看到
readyState !== 1就说明事件被意外提前触发(比如 mock 测试中伪造了onopen) - 注意:不要用
ws.CONNECTING这类常量名——它们不是全局变量,要写WebSocket.CONNECTING或直接用数字 - 某些旧版浏览器(如 iOS Safari 9.3)在
onopen中首次send()偶发失败,加个try/catch更稳妥
别在 onopen 里发大量数据或阻塞操作
WebSocket 连接建立后,首条消息往往用于同步状态或拉取快照。但如果在这儿一次性 send() 几 MB 的 JSON 或循环发上百条,可能触发服务端限流、前端缓冲区溢出,甚至让 onmessage 处理滞后。
立即学习“前端免费学习笔记(深入)”;
- 初始消息建议控制在几 KB 内,例如
{"type":"sync","last_seq":12345} - 需要批量数据时,改用服务端主动推送(如
{"type":"snapshot","data":[...]}),或分批次请求(发完一条等onmessage确认再发下一批) - 避免在
onopen里执行耗时计算(如加密 token、解析本地缓存),会拖慢首屏交互响应
重连场景下,onopen 仍适用,但需区分首次连接和重连
如果实现自动重连,每次成功重建连接都会触发 onopen。这时初始消息是否重发,取决于业务语义——比如鉴权 token 可能已过期,或服务端要求重新注册 client ID。
- 简单做法:在
onopen里统一发{"type":"reconnect","id":this.clientId},由服务端决定是否需要完整初始化 - 更严谨的做法:维护一个
isFirstConnection标志,在new WebSocket()前设为true,在onopen中判断并重置 - 注意:不要在
onclose或onerror里立刻 new WebSocket(),需加退避(如指数增长延迟),否则可能触发连接风暴
onopen 是个干净的入口点,但它的“干净”依赖于你没在里头塞进异步副作用、状态混乱的逻辑。真正容易被忽略的,是那些看似无关的上下文——比如你在封装一个 WebSocketClient 类,却把初始消息的构造逻辑放在实例化参数里,结果重连时用的还是旧参数。



















