sharedworker不能替代web push api,因其无法调用notification api,只能在页面主线程中请求权限并创建通知;它仅负责本地调度、去重、节流及向已授权且可见的标签页转发通知载荷。

SharedWorker 不能替代服务端 Push(如 Web Push API),也无法绕过浏览器对通知权限和推送服务的强制依赖——它只能做本地调度、去重、节流与 UI 协调,真正发通知仍需调用 Notification.requestPermission() 和 new Notification() 在页面主线程执行。
SharedWorker 里不能调用 Notification API
- 浏览器明确禁止在 Worker 线程(包括
SharedWorker)中调用Notification构造函数或.requestPermission(),会直接抛出DOMException: Permission denied或静默失败。 - 所有通知创建必须发生在拥有用户交互上下文(如 click、focus)的页面主线程中,这是安全模型硬性要求。
-
SharedWorker只能接收通知请求、判断是否该发、合并重复内容、决定发给哪个 tab,并通过port.postMessage()把格式化后的 payload 推送给已获授权且处于活跃/可见状态的页面。
如何设计一个真正可用的本地通知调度逻辑
- 页面首次加载时主动调用
Notification.requestPermission(),成功后向SharedWorker发送{ type: "register", clientId: "tab-xyz", permission: "granted" } -
SharedWorker维护一个Map<clientid port permission visibilitystate lastactive></clientid>,定期清理不可达或长期隐藏的端口 - 收到新通知请求(如
{ type: "notify", id: "order-123", title: "订单完成", body: "已发货" })时:- 检查
id是否已在 60s 内触发过,是则跳过(防刷屏) - 查找所有
permission === "granted"且visibilityState === "visible"的 port,只选一个(避免多 tab 同时弹窗) - 若无可见 tab,则缓存该通知,等任一 tab 切回前台时再触发(监听
document.visibilitychange后转发)
- 检查
- 不要尝试在 Worker 中做“延迟发送”:setInterval / setTimeout 在 Worker 中无法保证精度,切后台后会暂停;应由页面自己控制展示时机
Safari 和旧版 Chrome 的兼容陷阱必须手动兜底
- Safari 直到 macOS 13.3+ / iOS 16.4+ 才支持
SharedWorker,更早版本调用new SharedWorker()会静默失败(不抛错、不触发onerror) - 检测方式只能是:构造后立即
port.start()并发一条测试消息,1s 内没收到回执就判定不可用 - 降级方案不是“换用普通 Worker”,而是直接放弃共享调度,每个页面独立处理通知逻辑(但加全局
localStorage时间戳去重) -
localStorage本身不是跨域共享的,但同源下所有 tab 共享同一份存储,可用于简单节流:localStorage.setItem("last_notify_id", JSON.stringify({ id: "x", ts: Date.now() }))
真正节省 Push 成本的关键不在连接复用,而在于不让服务端发无效通知。SharedWorker 调度中心的价值,是把“该不该推”“推给谁”“推几次”的决策从服务端下沉到客户端——但这要求你有稳定可靠的在线状态同步机制,且必须接受:它永远只是辅助层,不是替代层。











