Worker 中无法访问 document 等主线程对象,因其运行在独立上下文;必须通过 postMessage 与主线程通信,DOM 操作只能由主线程执行;传大数据应使用 Transferable 避免克隆开销;Worker 内需用 self.onmessage/self.postMessage;路径需相对于 HTML 页面 URL。

Worker 里调用 document 就会报错,不是兼容性问题,是设计如此
只要在 Worker 脚本里写 document.getElementById、document.body 或任何带 document 的语句,运行时必然抛出 ReferenceError: document is not defined。这不是浏览器没支持好,而是规范强制禁止——Worker 运行在独立 JS 上下文,没有 window、document、localStorage、alert 等主线程专属对象。
常见错误场景:
- 把原本在
main.js里直接操作 DOM 的函数,原封不动复制进worker.js - 误以为
self.document存在(实际只有self.location和self.navigator可用) - 用
fetch请求后试图在 Worker 里解析 HTML 并插入节点(必须传回主线程做)
正确做法只有一条:Worker 只负责「算」,不负责「改」。所有 DOM 更新动作必须由主线程完成。
postMessage 传大数据时卡顿?检查是否用了结构化克隆而非 Transferable
默认情况下,worker.postMessage(data) 会对 data 做结构化克隆(structured clone),这意味着整个对象被深拷贝、序列化再反序列化。如果传的是几 MB 的 ArrayBuffer 或大型数组,主线程和 Worker 都要花时间复制内存,反而拖慢整体性能。
立即学习“前端免费学习笔记(深入)”;
高效替代方案是使用 Transferable 对象,把内存所有权直接移交,避免拷贝:
- 主线程发送时加第二个参数:
worker.postMessage(arrayBuffer, [arrayBuffer]) - Worker 接收后,该
ArrayBuffer在主线程中自动失效(变成byteLength === 0) - 仅支持
ArrayBuffer、MessagePort、ImageBitmap等少数类型 - 不支持普通对象、JSON、字符串——它们仍走结构化克隆
示例:处理图像像素数据
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// 主线程发送像素数据(移交所有权)
worker.postMessage(imageData.data.buffer, [imageData.data.buffer]);
主线程监听 onmessage 但收不到返回?确认通信双方都用了 self
Worker 脚本里必须用 self.onmessage 和 self.postMessage,不能省略 self。漏掉会导致静默失败——既不报错,也不触发回调。
典型错误写法:
-
onmessage = function(e) { ... }(全局变量赋值,Worker 环境无此全局绑定) -
addEventListener('message', ...)(需显式绑定到self,否则无效) - 主线程用
worker.addEventListener('message', ...)却没移除监听器,多次创建 Worker 后消息乱序
正确写法(Worker 内):
self.onmessage = function(e) {
const result = e.data.numbers.reduce((a, b) => a + b, 0);
self.postMessage({ sum: result });
};
主线程推荐用 worker.onmessage(简洁且自动绑定单次),或确保 addEventListener 后配对 removeEventListener。
路径写错导致 Worker 加载失败,错误信息藏在 DevTools 的 Console 里
Worker 构造函数的路径是相对于当前 HTML 页面 URL 的,不是相对于 JS 文件位置。比如 index.html 在根目录,js/app.js 里写 new Worker('workers/calc.js'),那浏览器就去找 /workers/calc.js;如果实际文件在 /js/workers/calc.js,就会 404。
容易忽略的细节:
- HTTP 状态码 404 不一定显示在页面上,但 DevTools → Console 里会有明确提示:
Failed to load worker script at … - 开发服务器(如 Vite、Webpack Dev Server)可能不默认托管
.js文件,需检查静态资源路由配置 - 使用 Blob URL 创建 Worker 可绕过路径问题,适合动态生成脚本,但调试困难
验证方式:直接在浏览器地址栏访问 Worker 脚本路径(如 http://localhost:5173/workers/calc.js),看能否正常返回 JS 内容。



















