sharedworker 是浏览器端实现全局唯一 websocket 长连接、降低服务端并发数的唯一可行方案,需同源 https/localhost 运行,websocket 必须在 worker 内创建并自主管理重连、心跳、状态同步与页面通信。

SharedWorker 必须在同源 HTTPS 或 localhost 下运行
浏览器会静默拒绝非安全上下文中的 SharedWorker 构造调用——连 onerror 都不会触发。开发和上线必须满足:
- 本地调试只能用
http://localhost:port,不能用file://协议 - 生产环境必须是
https://,哪怕同域名的http://也会直接失败 - Safari 仅支持 macOS 13.3+ / iOS 16.4+;旧版本需 fallback 到单页独连逻辑
WebSocket 实例必须在 SharedWorker 内创建,且仅一次
页面无法传递或共享 WebSocket 对象——它不可序列化,postMessage 会抛 DataCloneError。所有连接生命周期必须由 Worker 自主控制:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 在
shared-worker.js中执行new WebSocket(url),不能在页面中 new 后传入 - 收到第一个
{ type: "connect" }指令时检查ws是否已存在,避免重复创建 - 使用
Map维护port → clientId映射,每个页面接入时分配唯一clientId(推荐self.crypto.randomUUID()) - 服务端返回的消息必须带
targetClientId或topic,Worker 查表后只转发给匹配的port
重连、心跳、状态同步必须全部下沉到 SharedWorker 内部
把重连逻辑放在页面里会导致多个标签页同时发起重连请求,极易触发服务端频控或雪崩。关键点:
- 心跳用
setInterval在 Worker 内单点发起(如每 30s 发"ping"),服务端需响应"pong" - 连续两次无响应即
ws.close()并触发重连,避免假连 - 重连采用指数退避:
1s → 2s → 4s → …,上限设为30000(30 秒) - 断连期间缓存各页面的
subscribe请求,重连成功后自动重发 - 通过
port.postMessage({ type: "status", state: "connecting" })向所有页面广播连接状态
页面关闭时必须主动清理 port 和订阅关系
SharedWorker 不会自动感知页面关闭或刷新——port.onclose 在大多数浏览器中不触发,也不能依赖 window.onbeforeunload(页面崩溃时无效)。可靠做法是:
- 页面卸载前手动发
{ type: "disconnect", clientId: "win-abc123" } - SharedWorker 收到后从
Map中删除对应clientId,并清空其订阅列表 - 监听
self.onconnect时对每个port设置独立onmessagehandler,避免闭包变量污染 - 所有
ws.onopen/onmessage/onerror回调内加try...catch,否则未捕获异常会直接终止整个 SharedWorker 实例
port 打开”,但这个窗口可能只是后台标签页,甚至已冻结。它的定时器虽不受页面失焦影响,但一旦所有页面关闭,Worker 会在 10–30 秒后被浏览器回收——此时连接必然中断,新页面启动时必须能正确触发首次重连,而不是卡在“等待旧连接恢复”状态。










