贝利信息

javascript的web workers如何使用_它如何实现多线程编程以避免阻塞ui【教程】

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

Web Workers 不能直接操作 DOM,这是根本前提

很多初学者一上来就想在 Worker 里调用 document.getElementById 或修改 innerHTML,结果什么也不发生,控制台也没报错——因为 Web Workers 运行在完全独立的线程和全局环境里,没有 windowdocumentalert 等任何浏览器 DOM API。它只有自己的 self(等价于 globalThis),能用的只有 setTimeoutfetchatobstructuredClone 等有限的 API。

创建 Worker 的两种方式:内联脚本 vs 外部文件

必须用外部 JS 文件才能启动 Worker,这是硬性限制。所谓“内联”,只是用 Blob + URL.createObjectURL 模拟,本质仍是加载一个 URL。直接传字符串或函数会报 DOMException: Failed to construct 'Worker': Script URL must be of scheme 'http' or 'https'

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,但需开启跨域策略且兼容性差),所有数据都经序列化/反序列化传递。这意味着:

Worker 中的错误不会冒泡到主线程,必须手动监听

Worker 内抛出未捕获异常,只会静默失败,主线程完全感知不到。常见陷阱是:Worker 里 fetch 报错、JSON 解析失败、循环卡死,结果主线程一直等 onmessage 却收不到响应。

多线程不是银弹。Worker 启动有开销,频繁创建销毁反而比同步更慢;真正适合的是计算密集型任务(加密、图像处理、解析大 JSON)、可拆分的批量处理,而不是简单地把几个 for 循环塞进去。UI 是否卡顿,关键看主线程有没有长时间执行的 JS,而不在“用了多少线程”。