0—CONNECTING(未完成握手)、1—OPEN(就绪可通信)、2—CLOSING(关闭中)、3—CLOSED(已终止);需用事件驱动判断状态,不可依赖延时或直接校验数字。

readyState 的四个数值分别对应什么连接阶段
readyState 是 WebSocket 实例上的只读属性,返回 0、1、2 或 3,每个值严格对应一个生命周期阶段,不能靠“非零即真”或“大于0就可用”来判断:
-
0—CONNECTING:实例已创建,但 DNS 查询、TCP 握手、HTTP Upgrade 请求都还没完成,此时调用send()会直接抛出InvalidStateError -
1—OPEN:握手成功,连接就绪,send()和onmessage可安全使用 -
2—CLOSING:本地或远端已调用close(),关闭握手正在进行中;仍可能收到残留消息,但不能再发新数据 -
3—CLOSED:连接彻底终止(无论正常关闭还是异常断开),不可复用;必须新建 WebSocket 实例才能重连
注意:WebSocket.CONNECTING 等常量在 Android 4.4 WebView 或旧版 Safari 中可能未定义,建议直接用数字比较或自行定义映射对象。
为什么不能 new WebSocket() 后立刻检查 readyState === 1
构造函数是异步发起连接的,new WebSocket(url) 返回时 readyState 几乎总是 0,但此时连接远未完成——你无法预估它何时变成 1。固定延时(如 setTimeout(() => console.log(ws.readyState), 100))不可靠,网络抖动或服务响应慢会导致误判。
正确做法是依赖事件驱动:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 监听
onopen:触发即表示readyState已稳定为1,可立即send() - 监听
onerror:若发生在CONNECTING阶段,readyState通常仍为0,说明连接根本没建立成功 - 避免在
onopen外部写ws.send(),否则极易遇到InvalidStateError: Still in CONNECTING state
send() 和 close() 前必须校验 readyState 的场景
不加判断直接调用会引发运行时错误或静默失败。尤其在重连、心跳检测、用户主动断开等逻辑中,状态可能已变化。
- 发消息前只允许:
if (ws.readyState === WebSocket.OPEN)——CLOSING状态下send()不会报错但可能被丢弃,CLOSED下必抛异常 - 调用
close()前建议:if ([WebSocket.OPEN, WebSocket.CLOSING].includes(ws.readyState))—— 对CLOSED或CONNECTING实例重复close()无副作用,但没必要 - 重连逻辑里常见错误:仅凭
ws.readyState !== 1就新建连接,结果在CLOSING(2)时并发多个实例,或CLOSED(3)后未清理定时器导致内存泄漏
调试时如何快速识别当前状态
开发阶段别硬记数字,用可读字符串辅助排查:
- 定义状态映射:
const READY_STATE_MAP = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'] - 日志输出:
console.log('WS:', READY_STATE_MAP[ws.readyState], ws.readyState) - 在
onopen/onclose/onerror回调里打印,确认事件与状态是否匹配(例如onclose触发时readyState应为3) - 注意:
bufferedAmount在CLOSING阶段可能持续增长(待发送数据未清空),但它不是状态判断依据,仅反映发送队列压力
真正容易被忽略的是:状态切换不是原子的,onclose 触发和 readyState 变为 3 之间存在微小窗口;不要在 onclose 回调里假设 ws.readyState 已更新,应以事件本身为准,状态值仅用于后续逻辑分支控制。

















