WebSocket 连接建立前调用 send() 会静默丢弃消息,需缓存待发消息并在 onopen 后延迟发送;缓存采用队列+时间戳+重试标记,限制长度与超时,并支持 localStorage 持久化降级。

WebSocket 连接建立前调用 send() 会静默失败——此时 readyState 是 CONNECTING (0) 或未初始化,消息既不抛错也不返回,直接丢弃。所以必须在连接就绪前主动缓存待发消息,等 onopen 触发后再逐条发送。
缓存机制的核心逻辑
本质是“拦截 + 延迟投递”:所有发消息操作先不直连,而是统一进队列;只在连接真正打开后,再从队列里取、发、清空。
- 用数组(或
Deque)暂存待发消息,内容可以是原始字符串,也可以是已序列化的 JSON 对象 - 每次调用自定义
send()方法时,先检查ws.readyState === WebSocket.OPEN;满足则直发,否则推入缓存队列 -
onopen回调中启动一个轻量发送器,循环取出队列消息并调用原生ws.send(),注意用queue.shift()+ 微任务(如Promise.resolve().then())节制节奏,避免瞬间压垮连接
防积压的关键限制
队列不能无限增长,否则内存泄漏或重连后消息爆炸。需设置硬性边界:
- 长度限制:例如最多缓存 50 条,超出时丢弃最旧的一条(
queue.shift()) - 超时控制:每条消息记录时间戳,发送前检查是否超过 30 秒未发出,超时则丢弃并触发警告回调
- 可选重试标记:为每条缓存消息附加
retries: 0和唯一id,便于后续断线重发时追踪与去重
简易封装示例(无依赖)
以下是一个可直接运行的轻量类,覆盖连接、缓存、延迟发送全流程:
立即学习“Java免费学习笔记(深入)”;
(省略部分细节,聚焦主干逻辑)
- 构造时立即调用
connect(),内部创建WebSocket实例 - 维护
sendQueue = []和isSending = false状态标志 - 自定义
send(data)方法:若未就绪则push到队列;若就绪且空闲,则启动发送循环 -
onopen中仅设isSending = true,真正发送由独立函数驱动,支持暂停/恢复
移动端切后台的补充处理
在 iOS 或安卓 App 切后台时,系统可能主动关闭 WebSocket 连接。此时仅靠内存队列不够,需降级持久化:
- 监听
beforeunload或pagehide事件,在页面卸载前将未发队列序列化写入localStorage - 页面重新激活时,读取
localStorage并合并进内存队列(去重后) - 成功收到服务端 ACK 响应后,才从
localStorage中移除对应项,确保至少一次送达


















