Web Workers 不能直接操作 DOM,因其运行在独立线程且无 window、document 等浏览器 API,仅支持 setTimeout、fetch 等有限接口;通信依赖 postMessage/onmessage,数据需序列化,大对象应使用 transferable 优化。

Web Workers 不能直接操作 DOM,这是根本前提
很多初学者一上来就想在 Worker 里调用 document.getElementById 或修改 innerHTML,结果什么也不发生,控制台也没报错——因为 Web Workers 运行在完全独立的线程和全局环境里,没有 window、document、alert 等任何浏览器 DOM API。它只有自己的 self(等价于 globalThis),能用的只有 setTimeout、fetch、atob、structuredClone 等有限的 API。
创建 Worker 的两种方式:内联脚本 vs 外部文件
必须用外部 JS 文件才能启动 Worker,这是硬性限制。所谓“内联”,只是用 Blob + URL.createObjectURL 模拟,本质仍是加载一个 URL。直接传字符串或函数会报 DOMException: Failed to construct 'Worker': Script URL must be of scheme 'http' or 'https'。
- 推荐方式:单独建
worker.js文件,用new Worker('./worker.js') - 临时调试可用 Blob 方式,但注意每次都要
revokeObjectURL防止内存泄漏 - 模块化 Worker 需加
type: 'module'参数,且importScripts不支持 ES 模块语法
const workerCode = `
self.onmessage = function(e) {
const result = e.data * e.data;
self.postMessage({ result });
}
`;
const blob = new Blob([workerCode], { type: 'application/javascript' });
const worker = new Worker(URL.createObjectURL(blob));
worker.onmessage = (e) => console.log('平方结果:', e.data.result);
worker.postMessage(123); // 触发计算
// 别忘了清理
return () => URL.revokeObjectURL(blob);主线程与 Worker 通信只能靠 postMessage + onmessage
没有共享内存(除非用 SharedArrayBuffer,但需开启跨域策略且兼容性差),所有数据都经序列化/反序列化传递。这意味着:
- 传对象时,函数、undefined、Symbol、Date 对象、RegExp 等会被丢弃或转成空对象
- 大数据量(如百万级数组)会有明显序列化开销,不是“零成本”通信
- 想传 ArrayBuffer 或 TypedArray 可用
transferable选项避免拷贝,例如postMessage(data, [data.buffer]) - 不能用
await直接等 Worker 返回,必须用回调或封装成 Promise
Worker 中的错误不会冒泡到主线程,必须手动监听
Worker 内抛出未捕获异常,只会静默失败,主线程完全感知不到。常见陷阱是:Worker 里 fetch 报错、JSON 解析失败、循环卡死,结果主线程一直等 onmessage 却收不到响应。
立即学习“Java免费学习笔记(深入)”;
- 务必在 Worker 内加
self.onerror或try/catch包裹主逻辑 - 主线程也建议设
worker.onerror,但注意它只捕获初始化阶段错误(如脚本加载失败),运行时错误得靠postMessage主动上报 - 复杂任务建议加超时机制,比如主线程用
setTimeout检测是否响应超时
多线程不是银弹。Worker 启动有开销,频繁创建销毁反而比同步更慢;真正适合的是计算密集型任务(加密、图像处理、解析大 JSON)、可拆分的批量处理,而不是简单地把几个 for 循环塞进去。UI 是否卡顿,关键看主线程有没有长时间执行的 JS,而不在“用了多少线程”。











