sharedworker可实现多窗口websocket单链路复用,统一管理连接、心跳、重连与消息路由,通过clientid隔离上下文,并支持safari降级策略。

多窗口环境下,每个页面实例独立建立 WebSocket 连接,极易造成服务端连接数激增、客户端资源浪费(如重复心跳、冗余鉴权、内存占用上升)。共享线程(SharedWorker)是浏览器原生支持的跨上下文通信机制,可作为多个窗口共用的“连接中枢”,实现单链路复用,显著降低整体负载。
用 SharedWorker 统一管理 WebSocket 实例
SharedWorker 在独立线程中运行,生命周期独立于单个页面,多个窗口可通过 new SharedWorker() 获取同一实例的引用。所有窗口将消息发给 SharedWorker,由它统一维护一个 WebSocket 连接,并负责重连、心跳、鉴权续期等逻辑。
- 在 SharedWorker 脚本中创建并维持 WebSocket 实例(避免在页面中重复 new)
- 监听各窗口发来的消息(
port.onmessage),按 type 字段路由(如 "send"、"subscribe"、"unsubscribe") - 收到服务端消息后,通过对应窗口的 port 转发,确保数据精准投递
- 利用
self.onconnect捕获新窗口接入,动态维护 port 映射表(如 Map)
消息路由与上下文隔离
多个窗口共用一条链路,但业务数据需严格隔离——不能让 A 窗口收到 B 的私有推送。SharedWorker 需为每个接入窗口分配唯一 ID(如生成 UUID 或使用 window.name + timestamp),并在通信协议中显式携带上下文标识。
- 窗口首次连接时,向 SharedWorker 发送
{ type: "init", clientId: "win-abc123" } - 后续发送业务消息均附带
clientId,SharedWorker 转发时只推给匹配的 port - 服务端下发消息也应含
targetClientId或topic,SharedWorker 做白名单/订阅匹配,不盲目广播 - 窗口关闭前主动发
{ type: "disconnect" },SharedWorker 清理对应 port 和订阅关系
健壮性保障:重连、心跳与状态同步
SharedWorker 本身无自动持久化,需自行处理异常场景。WebSocket 断开后,SharedWorker 应执行指数退避重连;同时向所有关联窗口广播连接状态(如 { type: "status", state: "connecting" }),避免窗口误判为“服务不可用”而自行重建连接。
- 心跳由 SharedWorker 单点发起(如每 30s send("ping")),响应超时即触发重连
- 连接恢复后,重新发送各窗口的订阅指令(需缓存未确认的 subscribe 请求)
- SharedWorker 可监听
self.onerror和self.onoffline,辅助判断网络中断 - 窗口侧应监听 SharedWorker 的 onmessage 中的 status 类型消息,更新本地 UI 状态(如连接指示器)
兼容性与降级策略
SharedWorker 在 Safari 中长期受限(iOS 全面不支持,macOS Safari 16.4+ 才支持),需设计优雅降级:检测 typeof SharedWorker !== 'undefined',若不支持,则退回到每个窗口独立 WebSocket(保持功能可用),或结合 BroadcastChannel + localStorage 模拟轻量共享(仅同步状态,不共享连接)。
- 降级时,各窗口仍可通过 BroadcastChannel 通知彼此“已连接”,避免全部重连
- 关键业务消息(如登录态变更)用 localStorage + storage 事件同步,保证多窗口状态一致
- 构建时可将 SharedWorker 脚本单独打包,配合 Service Worker 缓存,提升加载可靠性










