sharedworker 内创建并独占管理 websocket 是实现全局唯一长连接、降低服务器负载的最有效方式,所有页面共用同一 tcp 连接,由 worker 全权负责生命周期、路由与恢复;websocket 不可跨上下文传递,须由 worker 自行实例化;需同源 https 环境,safari 有版本限制;消息通过 clientid 精准路由;重连与心跳必须下沉至 worker 内部,采用指数退避与单点心跳机制。

直接在 SharedWorker 内创建并独占管理 WebSocket 实例,是实现全局唯一长连接、降低服务器连接负载的最有效方式。关键不在于“共享对象”,而在于“统一出口”——所有页面共用同一个 TCP 连接,由 Worker 全权负责连接生命周期、消息路由与状态恢复。
必须由 SharedWorker 自行创建连接
WebSocket 对象不可跨上下文传递,页面中 new WebSocket() 后试图 postMessage 给 Worker 会失败(抛 DataCloneError)。正确做法是:
- SharedWorker 脚本(如 ws-manager.js)内直接调用 new WebSocket(url)
- 页面只发送指令,例如
{ type: "connect", url: "wss://api.example.com" } - Worker 收到后检查
ws?.readyState,仅当为CLOSED或未初始化时才新建实例 - 连接成功后,Worker 主动广播
{ type: "connected" }给所有已注册端口
连接复用依赖同源与安全上下文
SharedWorker 的复用能力受浏览器严格限制:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 必须运行在 HTTPS 或 localhost 下;
http://域名(即使同源)会被静默拒绝,file://协议完全不可用 - Safari 仅支持 macOS 13.3+ / iOS 16.4+,旧版本需降级为 BroadcastChannel + 主控页代理方案
- 所有页面引用 SharedWorker 的路径必须同源,且脚本 URL 保持一致(如
/assets/ws-manager.js)
消息分发需绑定 clientId 实现精准路由
单连接 ≠ 全广播。服务端下发的消息必须按业务隔离,避免 A 页面收到 B 页面的订单更新:
- 每个页面加载时生成唯一标识:
const clientId = crypto.randomUUID() - 首次通信即发送
{ type: "init", clientId },Worker 用Map存储clientId → port映射 - 服务端消息需携带
targetClientId或topic字段,Worker 查表后仅向匹配端口调用port.postMessage() - 页面关闭前主动发
{ type: "disconnect", clientId },Worker 清理映射及对应订阅关系
重连与心跳必须下沉至 Worker 内部
若把重连逻辑放在页面里,多个标签页可能同时触发重连请求,导致服务端雪崩;切后台后主线程定时器也会失效:
- 断线后使用指数退避:1s → 2s → 4s → …… 上限 30s,用
setTimeout实现,避免setInterval积压 - 心跳由 Worker 单点发起(如每 30 秒
ws.send("ping")),不依赖页面活跃状态 - 连续 2 次未收到服务端 pong 响应,则主动
ws.close()并触发重连流程 - 所有
onopen/onmessage/onerror回调内加try...catch,防止未捕获异常终止整个 Worker










