sharedworker需用javascript实例化且满足https/localhost、同源、独立js文件三要素;构造失败主因是环境或路径问题,验证需通过chrome://inspect查看;页面端必须显式调用port.start()才能通信;脚本中无window/document,调试需用self.console.log();变量共享但无锁,竞态需手动处理;safari 16.4+才支持,旧版需降级方案。

SharedWorker 不是 HTML 创建的,而是用 JavaScript 实例化的;HTML 页面只是加载并运行调用它的脚本。直接在 <script></script> 里写 new SharedWorker() 就行,但必须满足 HTTPS/localhost、同源、独立 JS 文件这三要素,否则静默失败或报错。
SharedWorker 构造失败的常见原因和验证方法
页面执行 new SharedWorker('worker.js') 后没反应,不是“代码没写对”,大概率是环境或路径问题:
-
typeof SharedWorker === 'undefined':浏览器不支持(如 Safari file:// 协议下 - DevTools 的 Network 面板里
worker.js显示 404:路径不是同源绝对路径,比如页面在/admin/下却写'./shared-worker.js',实际请求的是/admin/shared-worker.js - 脚本响应头缺失
Content-Type: application/javascript:Chrome 会拒绝加载,Network 面板里 status 显示 (blocked:mime-type) -
localhost:3000和127.0.0.1:3000被视为不同源:连实例都建不起来,更别说共享
验证是否真正启动:打开 Chrome DevTools → chrome://inspect → 点 “Shared Workers” → 看列表里有没有你的脚本名。没有?说明至少一个页面还没成功调用 port.start(),或者脚本根本没执行到 self.onconnect。
页面端必须显式调用 port.start() 才能通信
这是最常被跳过的一步。worker.port 默认处于暂停状态,不调 start(),消息就卡在通道里,onmessage 根本不会触发。
- 正确顺序:
worker.port.start()必须在onmessage绑定之后、首次postMessage()之前执行 - 即使写了
worker.port.onmessage = ...,也不能依赖浏览器自动启动;显式调用才可靠 - 如果用
addEventListener('message', ...),同样得手动port.start() - 页面卸载前可选
port.close(),避免残留监听器,但不是必须
示例片段:
const worker = new SharedWorker('/workers/state.js');
const port = worker.port;
port.start(); // ⚠️ 必须放这里
port.onmessage = (e) => console.log(e.data);
port.postMessage({ type: 'init' });
SharedWorker 脚本里不能用 window 或 document,调试要换地方
SharedWorker 运行在独立线程,全局对象是 self,没有 DOM API,所有操作靠 postMessage 和事件驱动。
-
console.log()输出不会出现在页面 Console,得切到 DevTools 的 Shared Worker 专用面板(chrome://inspect或 Firefox 的about:debugging) - 要用
self.console.log()更稳妥,避免某些环境报console is not defined -
localStorage可读写,但受同源限制;fetch、setTimeout、WebSocket都可用 - 别写
self.close()—— 它不会终止 Worker,反而可能中断当前端口通信
脚本开头加一句 self.console.log('shared-worker ready'),是最简单的启动确认方式。
多个页面共享变量但无锁,竞态必须自己处理
SharedWorker 内顶层声明的 let count = 0 或 const cache = new Map() 是真共享,所有端口共用同一内存地址。但这不等于线程安全。
-
count++不是原子操作:两个页面几乎同时执行,可能只加了 1 次 -
self.clients.matchAll()返回的是 Promise,结果可能过期;遍历前最好用await并过滤掉已关闭的 port - 广播时若某个 port 已断开,
port.postMessage()会抛错,需包try/catch - 简单防并发:用标记位
if (!busy) { busy = true; /* 修改 state */; busy = false; } - 更稳做法:把变更推入队列,用
requestIdleCallback或单次setTimeout串行处理
真正落地时,别指望 SharedWorker 自己扛住高并发写入 —— 它适合协调,不适合当数据库。
最后提醒:Safari 16.4+ 才支持,旧版本必须 fallback 到 BroadcastChannel + localStorage 监听 storage 事件;HTTPS 或 localhost 是硬门槛,开发阶段别用 file:// 测试;脚本路径必须绝对且同源,相对路径极易导致多个实例并存、状态割裂。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











