Web Workers 是浏览器中唯一真正并行执行 JS 的机制,基于独立 JS 环境与消息通信,通过 postMessage/onmessage 传递序列化数据,无法访问 DOM、localStorage 等,仅支持同源脚本。

Web Workers 不是 JavaScript 的多线程——它没有共享内存,也不能直接操作 DOM,但它是浏览器里唯一能真正并行执行 JS 代码的机制。
Web Worker 的本质:独立 JS 环境 + 消息通信
每个 Worker 运行在单独的全局上下文(self 代替 window),有自己的事件循环、堆内存和执行栈。主线程和 Worker 之间只能通过 postMessage() 和 onmessage 传递可序列化的数据(或转移 ArrayBuffer)。
- 不能访问
document、localStorage、XMLHttpRequest(但可用fetch) -
console.log在 Worker 中有效,输出会出现在开发者工具的 “Workers” 标签页下 - Worker 脚本必须是同源的,且不能是
data:或blob:URL(除非用Blob URL显式构造)
如何创建并使用 Dedicated Worker
最常用的是专用 Worker(DedicatedWorkerGlobalScope),一对一绑定主线程。
第一步:写一个独立 JS 文件(比如 worker.js):
立即学习“Java免费学习笔记(深入)”;
self.onmessage = function(e) {
const data = e.data;
// 假设做 CPU 密集型计算
let result = 0;
for (let i = 0; i < data.n; i++) {
result += i * i;
}
self.postMessage({ result });
};第二步:在主线程中实例化并通信:
const worker = new Worker('worker.js');
worker.onmessage = function(e) {
console.log('计算结果:', e.data.result);
};
worker.onerror = function(e) {
console.error('Worker 报错:', e.message, e.filename, e.lineno);
};
worker.postMessage({ n: 1000000 }); // 启动计算
- 注意路径是相对于 HTML 页面的,不是相对于当前 JS 文件
- 如果要用模块化 Worker,需用
new Worker('worker.js', { type: 'module' }),且脚本中用import - 调用
worker.terminate()可立即销毁 Worker,释放资源;不终止的话,它会一直存活到页面卸载
SharedWorker 和 Service Worker 的关键区别
别混淆三类 Worker:
-
DedicatedWorker:仅被创建它的脚本访问,适合单任务并行(如解析大 JSON、加密、Canvas 预处理) -
SharedWorker:可被同源多个页面/iframe 共享,用port.postMessage()通信,需手动port.start();已逐渐被弃用,Chrome 95+ 默认禁用,不建议新项目使用 -
ServiceWorker:用于拦截网络请求、离线缓存,生命周期由浏览器控制,与页面无直接绑定,不能访问self.document也不支持postMessage直接传对象(需走ClientAPI)
如果你只是想把耗时计算搬出主线程避免卡顿,只用 DedicatedWorker 就够了。
常见错误和性能陷阱
实际用 Worker 时,最容易栽在“以为能加速一切”上:
- 小任务反而更慢:启动 Worker 有开销(约几毫秒),数据序列化/反序列化也有成本;简单运算(如
Math.sqrt(123))放 Worker 里纯属负优化 - 误传大对象:传一个 10MB 的
JSON.stringify后的字符串,主线程和 Worker 都要复制一份内存;应尽量用Transferable(如postMessage(data, [arrayBuffer]))来零拷贝转移二进制数据 - 忘记错误隔离:Worker 内部报错不会冒泡到主线程,必须监听
worker.onerror或在 Worker 里加try/catch + postMessage主动上报 - 内存泄漏:Worker 中的闭包、定时器、未注销的事件监听器都会持续占用内存;尤其注意
setInterval忘记clearInterval
真正需要 Worker 的场景很具体:长时间运行的数值计算、图像/音视频帧处理、大型数据结构遍历、加密解密、WASM 模块调用——其它时候,优先考虑 requestIdleCallback 或分片(setTimeout 分批)更轻量。











