Web Workers 是浏览器提供的独立执行环境,非 JavaScript 多线程,不共享内存、不可操作 DOM,仅通过 postMessage 进行消息通信。

Web Workers 不是 JavaScript 的多线程,而是浏览器提供的独立执行环境;它不能直接操作 DOM,也不能共享内存,本质是“进程隔离 + 消息通信”。
Web Worker 为什么不能直接访问 document 或 window
Worker 脚本运行在独立的全局上下文中(WorkerGlobalScope),与主线程完全隔离。这意味着:
-
document、window、localStorage、fetch(部分浏览器支持,但需注意 CORS 和凭据)等 API 均不可用 - 主线程和 Worker 之间**不共享变量或对象引用**,只能通过
postMessage()传递可序列化的数据(或Transferable对象,如ArrayBuffer) - 试图访问
document会直接抛出ReferenceError: document is not defined
如何正确创建并通信一个 Dedicated Worker
必须将 Worker 逻辑写在**单独的 JS 文件中**(不能是内联字符串或箭头函数),然后用 new Worker() 实例化:
// main.js
const worker = new Worker('./worker.js');
worker.postMessage({ type: 'start', data: [1, 2, 3] });
立即学习“Java免费学习笔记(深入)”;
worker.onmessage = (e) => {
console.log('主线程收到:', e.data);
};
worker.onerror = (e) => {
console.error('Worker 执行出错:', e.message);
};
对应 worker.js 中必须监听 onmessage 并调用 postMessage() 回传:
// worker.js
self.onmessage = function(e) {
const result = e.data.data.map(x => x * 2);
self.postMessage({ type: 'done', result });
};
- 不能用
this或window,必须用self引用当前 Worker 全局对象 - 若需终止,主线程调用
worker.terminate(),Worker 内部调用self.close() - 路径必须是同源的,且不能是
file://协议(需 HTTP(S) 服务)
SharedWorker 和 ServiceWorker 有什么关键区别
三者都是 Worker,但生命周期、作用域和用途完全不同:
-
DedicatedWorker:一对一绑定,仅创建它的脚本可通信,关闭页面即销毁 -
SharedWorker:多个页面/iframe 可连接同一实例,用port.start()和port.postMessage()通信,需手动管理端口 -
ServiceWorker:注册后可拦截网络请求、实现离线缓存,运行在独立线程但受严格生命周期控制(如 install、activate、fetch 事件),且只支持 HTTPS(localhost 除外)
别误把 SharedWorker 当作“共享内存方案”——它依然靠消息传递,只是多路复用一个 Worker 实例。
常见陷阱:JSON 序列化限制与性能盲区
默认情况下,postMessage() 会深拷贝数据(结构化克隆算法),大对象(如百 MB 级 ArrayBuffer)会卡顿主线程:
- 传递图像像素数据时,务必用
postMessage(data, [data.buffer])进行零拷贝转移(data.buffer将从原上下文移除) - 函数、
Date、RegExp、undefined、循环引用对象无法被克隆,会静默丢弃字段或报错 - 频繁小消息(如每帧发一次坐标)可能引发通信瓶颈,建议批量合并或改用
MessageChannel分离通道
真正需要“并发计算”的场景(比如音频 FFT、大型数组排序),Worker 是可靠选择;但想绕过单线程做 UI 动画或状态同步?它解决不了——那得靠 requestIdleCallback 或更细粒度的任务调度。











