必须设最大重连次数,否则网络彻底断开时会无限循环导致内存和CPU耗尽;maxRetries为必填项,推荐生产环境设为10,高敏感场景降为5,禁用-1或Infinity;指数退避参数建议initialDelay=1000ms、backoffFactor=1.6、maxDelay=30000ms;每次setTimeout前需clearTimeout旧定时器;仅对非正常关闭码(event.code≥1000)重连。

必须设最大重连次数,否则网络彻底断开时会无限循环,吃光内存和 CPU。
为什么 maxRetries 不是可选项而是必填项
无限重连在真实场景中只会带来三类问题:客户端定时器堆积、服务端连接洪峰、用户设备发热卡顿。尤其当用户切换到飞行模式或拔掉网线时,setTimeout 会持续注册却永不执行,最终触发内存泄漏警告。
- 生产环境建议硬性限制为
maxRetries = 10,足够覆盖绝大多数临时抖动(如电梯、地铁进隧道) - 若业务对“连接感知”要求极高(如交易下单页),可降为
5,失败后直接提示用户手动刷新 - 绝对不要设为
-1或Infinity—— 即便配置了指数退避,也无法阻止底层定时器对象持续增长
指数退避延迟怎么算才不炸服务器
公式本身简单:delay = Math.min(initialDelay * Math.pow(backoffFactor, attempt), maxDelay),但关键在参数取值是否贴合真实网络条件。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
-
initialDelay推荐1000(1 秒),比 100ms 更稳妥:避免握手未完成就触发重连 -
backoffFactor用1.6比2更平滑,第 6 次重连延迟约 10.5 秒,而非 32 秒,兼顾恢复速度与压力控制 -
maxDelay设为30000(30 秒)是多数 CDN 和 LB 的空闲超时默认值,再长无意义 - 每次调用
setTimeout前必须先clearTimeout(this.reconnectTimer),否则旧定时器可能在新连接建立后误触发
onclose 里怎么安全判断是否该重连
不是所有 onclose 都该触发重连 —— 例如用户主动调用 ws.close(1000, "user logout"),此时重连就是逻辑错误。
- 只对非正常关闭码重试:
event.code >= 1000 && event.code (标准关闭范围是 1000–1015,但很多网关会返回 1005/1006) - 明确排除
1000(正常关闭)、4000+(服务端自定义拒绝,如鉴权失败,重连无用) - 优先用
addEventListener('close', handler)绑定,别反复赋值ws.onclose = ...,否则容易漏掉首次连接失败的onclose - 检查
ws.readyState === WebSocket.CONNECTING || ws.readyState === WebSocket.CLOSED,避免在OPEN状态下误启动重连流程
重连过程中如何防止消息错乱和重复订阅
重连不是“断了再连”,而是“旧连接未死、新连接已生”的过渡期,这时最容易出数据错位。
- 发消息前永远加守卫:
if (ws.readyState !== WebSocket.OPEN) return,别信“我刚 new 完它就该 ready” - 给每个连接实例打唯一标记:
ws._id = Date.now() + '-' + Math.random().toString(36).substr(2, 9) - 在
onmessage中过滤:if (msg.connectionId !== this.currentWs?._id) return,丢弃旧连接残留包 - 重连成功后,**不要自动重发未确认消息** —— 除非你的协议层有消息 ID + ACK 机制,否则盲目重发会破坏顺序语义
真正难的不是写对指数公式,而是在 onclose 触发瞬间,准确区分“该重连”“该静默”“该报错”——这需要结合关闭码、readyState、业务上下文三者交叉判断,少一个都可能让重连变成雪崩开关。

















