如何利用 SharedWorker 构建多标签页共享的数据缓存层降低网络请求

小枫同学_9050

小枫同学_9050

2026-05-03

504人浏览

原创

sharedworker 不能直接读写 localstorage 或发起 fetch,但可作为调度中枢实现多标签页内存缓存共享与请求去重;需用 map 存带 ttl 的原始 js 值,通过 pendingrequests 实现请求合并,监听 port.onclose 清理引用,并为 safari 提供 broadcastchannel + localstorage 降级方案。

如何利用 sharedworker 构建多标签页共享的数据缓存层降低网络请求

SharedWorker 本身不能直接读写 localStorage 或发起网络请求(如 fetch),但它能作为调度中枢,把缓存逻辑收口到一个线程里,让多个标签页共用同一份内存缓存 + 统一去重请求。关键不是“它缓存了什么”,而是“它阻止了多少重复请求”。

SharedWorker 里怎么存缓存数据?别碰全局变量

SharedWorker 脚本运行在独立上下文,self 下可以声明普通对象或 Map,但必须注意:所有页面共享的是同一个实例,所以缓存结构要可并发访问、不依赖页面生命周期。

  • Map 存键值对比 Object 更安全,避免原型污染和隐式类型转换(比如 cache.set('1', 'a')cache.set(1, 'b') 是两个不同 key)
  • 不要用 JSON.stringify() 后存字符串——序列化/反序列化开销大,且丢失 Date、Map、Set 等类型;缓存原始 JS 值即可
  • 缓存条目需带 TTL(时间戳),每次 get 前检查是否过期;不建议依赖 setTimeout 清理,因为 SharedWorker 可能长期空闲,定时器不会触发
  • 示例:
    const cache = new Map(); // key: string, value: { data, expiresAt }

怎么让多个标签页的 fetch 请求不重复发?靠请求去重队列

页面 A 和 B 同时调用 get('/api/user/123'),SharedWorker 必须只发一次网络请求,再把结果分发给两者。这需要“请求合并”而非“简单缓存查表”。

灵枢SparkVertex
灵枢SparkVertex

一款AI开发辅助工具,主要用于零代码AI应用开发平台,适合需要提升相关任务效率的用户。

下载
  • 收到请求时,先检查 cache.has(key);命中则直接回传,不进队列
  • 未命中时,生成唯一 requestId(如 Date.now() + Math.random()),并以 URL 为 key 存入 pendingRequests.set(url, { requestId, resolve, reject, ports: [port] })
  • 若同一 URL 已在 pending 中,不发新请求,只把当前 port 推入 ports 数组
  • 请求返回后,遍历 ports 逐个 port.postMessage({ requestId, data }),再从 cachependingRequests 中清理
  • 注意:fetch 必须在 SharedWorker 内发起,页面侧只传参数,不传 AbortController —— 它无法跨线程传递

页面卸载时如何避免缓存失效或请求悬空?主动 close port 并清理

用户关掉某个标签页,其对应的 port 会断开,但 SharedWorker 若还拿着这个 port 引用并尝试 postMessage,会静默失败,甚至卡住整个响应流程。

  • 页面侧要在 beforeunload 中显式调用 worker.port.close(),触发 SharedWorker 的 port.onclose
  • SharedWorker 中监听 port.onclose = () => { pendingRequests.forEach(req => req.ports = req.ports.filter(p => p !== port)) }
  • 每个 pending 请求必须设超时(如 10 秒),超时后调用所有 resolve/reject 并清空该条目,否则队列会越积越多
  • 不建议用 self.onoffline 判断网络中断——它只反映浏览器整体离线状态,不是连接粒度的

为什么 Safari 上容易 fallback?它的 SharedWorker 支持不完整

Safari 自 15.4 起才支持 SharedWorker,且存在两个硬伤:不支持 SharedWorker 构造函数的 name 选项;port.start() 行为不稳定,有时需手动调用两次才能激活消息通道。

  • 检测兼容性必须用 typeof SharedWorker === 'function',不能只靠 try/catch
  • 降级方案不是“不用缓存”,而是退回到页面级内存缓存 + localStorage 时间戳比对(例如存 __cache_user_123_ts
  • 如果项目必须支持旧 Safari,建议用 BroadcastChannel 搭配 localStorage 事件做轻量同步,虽然有延迟,但比完全无共享强
  • 不要在 SharedWorker 里调用 indexedDB.open——Safari 对 SharedWorker 中的 IndexedDB 支持极差,容易报 InvalidStateError

真正难的不是写通 SharedWorker,而是设计好请求生命周期的边界:什么时候算“一个请求结束”,什么时候该“广播状态变更”,以及哪个环节出错会导致整个队列卡死。这些细节不写进代码注释里,半年后你自己都看不懂。

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

4106

5

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

2023.07.04

1049

3

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

2023.07.04

4004

6

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

2023.09.01

820

4

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

1716

5

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

2023.09.04

3005

4

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

2023.09.12

3913

6

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

2023.09.20

2480

5

java访问控制修饰符介绍
java访问控制修饰符介绍

java访问控制修饰符有四种,分别是public、protected、private、默认访问修饰符。详细介绍:1、public,public是最宽松的访问控制修饰符,被修饰的类、方法和变量可以被任何其他类访问,当一个类、方法或变量被声明为public时,它们可以在任何地方被访问,无论是同一个包中的类还是不同包中的类;2、protected修饰符等等。

2023.09.20

828

7

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
誉天教育RHCE视频教程
誉天教育RHCE视频教程

共9课时 | 1.7万人学习

尚观Linux RHCE视频教程(二)
尚观Linux RHCE视频教程(二)

共34课时 | 6.8万人学习

尚观RHCE视频教程(一)
尚观RHCE视频教程(一)

共28课时 | 5.8万人学习