Web Workers 不能直接操作 DOM,因其运行在独立线程且无 window、document 等浏览器 API,仅支持 setTimeout、fetch 等有限接口;通信依赖 postMessage/onmessage,数据需序列化,大对象应使用 transferable 优化。
很多初学者一上来就想在 Worker 里调用 document.getElementById 或修改 innerHTML,结果什么也不发生,控制台也没报错——因为 Web Workers 运行在完全独立的线程和全局环境里,没有 window、document、alert 等任何浏览器 DOM API。它只有自己的 self(等价于 globalThis),能用的只有 setTimeout、fetch、atob、structuredClone 等有限的 API。
必须用外部 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')
revokeObjectURL 防止内存泄漏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);没有共享内存(除非用 SharedArrayBuffer,但需开启跨域策略且兼容性差),所有数据都经序列化/反序列化传递。这意味着:

transferable 选项避免拷贝,例如 postMessage(data, [data.buffer])
await 直接等 Worker 返回,必须用回调或封装成 PromiseWorker 内抛出未捕获异常,只会静默失败,主线程完全感知不到。常见陷阱是:Worker 里 fetch 报错、JSON 解析失败、循环卡死,结果主线程一直等 onmessage 却收不到响应。
self.onerror 或 try/catch 包裹主逻辑worker.onerror,但注意它只捕获初始化阶段错误(如脚本加载失败),运行时错误得靠 postMessage 主动上报setTimeout 检测是否响应超时多线程不是银弹。Worker 启动有开销,频繁创建销毁反而比同步更慢;真正适合的是计算密集型任务(加密、图像处理、解析大 JSON)、可拆分的批量处理,而不是简单地把几个 for 循环塞进去。UI 是否卡顿,关键看主线程有没有长时间执行的 JS,而不在“用了多少线程”。