SharedWorker 不能直接发起网络请求,而是作为调度中枢统一收口、去重、缓存、限流;所有页面须通过 postMessage 发送请求指令,Worker 决定是否真实发出,并合并重复请求、命中缓存即分发结果,不支持时降级为 BroadcastChannel + 主控页代理。

必须由 SharedWorker 统一接管请求入口
所有页面不再直接调用 fetch(),而是通过 port.postMessage({ type: 'fetch', url, method, body }) 向 SharedWorker 发起指令。Worker 收到后才决定是否真正发出请求。
- 同一 URL + 相同参数的请求,在 pending 队列中只保留一个,其余页面的 port 被挂载到该请求的回调列表里
- 命中缓存(带 TTL 的 Map 存储)则跳过网络层,直接分发结果
- Worker 内使用
self.fetch()(仅部分现代浏览器支持)或降级为 BroadcastChannel + 主控页代理(兼容 Safari 等不支持 Worker fetch 的环境)
用 Map + TTL 实现轻量内存缓存
SharedWorker 中声明一个全局 const cache = new Map(),每个条目形如:{ data, expiresAt: Date.now() + 60_000 }(默认缓存 1 分钟)。
- 不序列化数据:直接存 JS 值(支持
Date、Map、ArrayBuffer等原生类型) - 每次
get(key)前检查expiresAt,过期即删除并返回未命中 - 避免用
setTimeout清理——SharedWorker 可能长期空闲,定时器不会触发
请求合并与并发控制
当多个页面同时请求 /api/user/123,SharedWorker 不会发多次,而是合并为一次,并将响应广播给所有等待方。
- 用
pendingRequests.set(url, { resolveList: [port1, port2], controller: AbortController })管理待处理请求 - 请求成功后遍历
resolveList,逐个port.postMessage({ url, data, timestamp }) - 主动取消机制:任一页面关闭前发
{ type: 'cancel', url },Worker 清理对应resolveList并调用controller.abort()
降级与兼容性兜底
SharedWorker 在 Safari 旧版本、某些 WebView 或 HTTP 环境下不可用,必须有 fallback。
- 检测失败时自动启用
BroadcastChannel('req-bus')+ 主控页代理模式:首个打开的页面承担请求职责,其余页通过广播协调 - HTTP 环境下静默退化为单页独立请求,不报错也不阻塞业务
- 对 localStorage 的读写降级由主页面完成,SharedWorker 仅做状态同步

















