sharedworker 是浏览器中唯一支持跨标签页复用单条 websocket/mqtt 连接的机制,通过集中管理连接、心跳、重连及消息路由,显著降低服务端并发压力;需配合 broadcastchannel 协同就绪状态,并设计降级方案应对不支持场景。

SharedWorker 是目前浏览器中唯一能跨标签页复用单个长连接的机制,它把 WebSocket 或 MQTT 连接逻辑完全收束到一个共享执行环境中,让多个页面共用一条底层 TCP 连接。这样服务端看到的不是几十个标签页发起的几十个连接,而只是一个连接,显著降低并发连接数、握手频次和资源开销。
必须由 SharedWorker 自主创建并管理连接
页面不能 new WebSocket() 后传给 Worker —— WebSocket 实例不可序列化,postMessage 会直接报错。所有连接动作(包括重连、心跳、订阅)都必须在 SharedWorker 内完成:
- Worker 初始化时检查
ws.readyState,仅在CLOSED或CONNECTING状态下才new WebSocket() - 使用
setTimeout实现指数退避重连(1s → 2s → 4s…上限 30s),避免多页面同时触发重连风暴 - 心跳由 Worker 单点发起(如
setInterval(() => ws.send('ping'), 30000)),不依赖页面是否处于前台 - 每个
onmessage、onerror、onclose回调内加try...catch,防止未捕获异常导致 Worker 崩溃
消息路由需精准匹配,避免广播泛滥
服务端下发的消息通常带 targetClientId 或 topic 字段,Worker 不能全量转发。必须维护一张映射表:
- 页面首次连接时生成唯一
clientId(推荐crypto.randomUUID()),通过port.postMessage({ type: 'register', clientId })注册 - Worker 收到服务端消息后,解析
targetClientId,查表找到对应port,再调用port.postMessage(data) - 页面关闭前主动发
{ type: 'disconnect', clientId },Worker 清理映射项与订阅关系
配合 BroadcastChannel 实现连接就绪协同
SharedWorker 本身不支持直接构造 WebSocket(部分浏览器会抛 SecurityError),更稳妥的做法是:由一个“主控页”建立连接,并用 BroadcastChannel 广播状态,Worker 监听后统一响应其他页面请求:
- 所有页面 + SharedWorker 使用同一频道名,如
new BroadcastChannel('app-socket-bus') - 主控页连接成功后广播
{ type: 'ws-open' };Worker 收到后才开始处理各页面的connect请求 - 主控页断开时必须广播
{ type: 'ws-closed' },否则 Worker 可能继续向已失效连接发消息 - Worker 内建议在
onconnect回调开头就创建BroadcastChannel,确保监听时机早于页面通信
降级与容错设计不可少
SharedWorker 不是万能容灾方案——页面全部关闭后,Worker 会在 10–30 秒后被回收,此时连接自然中断。需提前准备 fallback:
- 页面初始化时捕获
new SharedWorker()异常(如浏览器不支持或 HTTPS 不满足),自动降级为localStorage + storage事件做轻量状态同步 - 高并发场景(如活跃标签页超 150 个)可改用 BroadcastChannel 分片调度,避免 Worker 成为性能瓶颈
- 服务端应支持连接复用标识(如
Sec-WebSocket-Protocol或自定义 header),便于识别并合并来自同一 SharedWorker 的连接











