SharedWorker 是唯一可行的跨页面连接中枢,通过单条长连接+多路复用实现“全局唯一网络连接池”效果,需同源一致路径创建、Worker内统一管理WebSocket、分配clientId隔离上下文、内置健壮性机制,并注意HTTPS/Safari兼容性限制。

SharedWorker 本身不提供“网络连接池”能力,浏览器也不允许它直接管理多个 WebSocket 或 HTTP 连接实例。所谓“全局唯一的网络连接池”,在前端语境下实际是指复用单条长连接 + 统一调度多页面请求,核心目标是降低服务端并发连接数、避免重复鉴权与心跳开销。这不是传统后端意义上的连接池(如数据库连接池),而是一种连接中枢模式。
SharedWorker 是唯一可行的跨页面连接中枢
普通 Worker 每个标签页新建一个实例;Service Worker 无法主动维持长连接,只响应 fetch/push 等事件;只有 SharedWorker 被设计为同源多上下文(tab/iframe/window)共用同一执行环境。只要还有一个同源页面打开,Worker 就持续运行,其内部维护的 WebSocket 实例就能保持。
- 所有页面必须用完全一致的路径创建实例:
new SharedWorker('./ws-manager.js')(协议、域名、端口、文件名缺一不可) - WebSocket 必须在 Worker 内创建,且仅执行一次;页面不能传入或共享 WebSocket 对象——它不可序列化,
postMessage会报DataCloneError - Worker 生命周期独立于单个页面:页面刷新、崩溃、切后台不影响其运行,连接稳定性由此提升
用单链路模拟“池”的行为:统一收发 + 上下文隔离
一条 TCP 连接不等于只能服务一个业务流。SharedWorker 通过显式标识实现逻辑上的“多路复用”,效果接近轻量级连接池。
- 每个页面接入时,Worker 分配唯一
clientId(推荐self.crypto.randomUUID()),存入Map<port clientid></port> - 页面发消息必须携带
clientId,例如:{ type: "send", data: {}, clientId: "win-abc123" } - 服务端返回的消息需含
targetClientId或topic,Worker 查表后只转发给匹配的port,不广播 - 页面关闭前主动发
{ type: "disconnect", clientId: "win-abc123" },Worker 清理映射与订阅关系
连接健壮性必须全部下沉到 Worker 内部
重连、心跳、状态同步若放在页面侧,会导致多个标签页同时触发重连请求,引发服务端雪崩;切后台后主线程定时器也会失效。
- 使用
setInterval单点发送"ping",服务端需响应"pong";连续两次无响应即断连重试 - 断连后执行指数退避重连(1s → 2s → 4s → … 最大 30s),防止密集重连冲击
- 重连成功后,自动重发各窗口缓存的
subscribe请求(需在 Worker 内维护订阅快照) - 通过
port.postMessage({ type: "status", state: "connecting" })向所有页面同步连接状态,UI 可据此更新指示器
兼容性与降级要点
SharedWorker 并非万能,需主动应对现实限制。
- 必须运行在 HTTPS 或
http://localhost下;file://协议和 HTTP 域名均会静默失败 - Safari 仅支持 macOS 13.3+ / iOS 16.4+,旧版本需降级为单页独连(页面内自行管理 WebSocket)
- Worker 内无
window、document、localStorage,只能用self和postMessage通信 - 所有
ws.onopen/onmessage/onerror回调内必须加try...catch,否则未捕获异常会导致整个 Worker 退出

















