Web Worker 中无法访问 document 或 window,因其全局作用域不包含 DOM 相关对象;应通过 postMessage 通信、状态数据抽象、OffscreenCanvas 和 CustomEvent 实现主线程与 Worker 的解耦协作。

Web Worker 里访问 document 或 window 会直接报 ReferenceError: document is not defined,这不是加载慢、没等好,而是 Worker 全局作用域(WorkerGlobalScope)压根就没有这些对象——连 Element、CSSStyleSheet、localStorage 都不存在。破局的关键不是“绕过限制”,而是重构协作方式。
用 postMessage 做唯一可信通道
主线程和 Worker 之间没有共享内存、不能传函数、也不能共享 DOM 节点。所有通信必须走 postMessage + onmessage,数据经结构化克隆(structured clone),只支持纯数据:
- ✅ 可传:普通对象、数组、Date(转为毫秒数)、Map/Set(需手动序列化)、ArrayBuffer(推荐用
transfer避免拷贝) - ❌ 不可传:DOM 节点、
function、RegExp、Error、Window、document - 主线程收到消息后,自己调用
document.querySelector或更新el.textContent,Worker 只管算、不碰 UI
把 UI 状态抽象成可序列化数据
不要让 Worker “知道”按钮在哪、进度条怎么画,而是定义清晰的状态模型:
- 例如上传任务状态:
{ id: 'task-123', status: 'uploading', progress: 72, error: null } - Worker 处理完计算或请求后,只发这个对象;主线程监听并映射到真实 DOM 元素
- 状态字段必须是字符串、数字、布尔、null 或嵌套的纯对象/数组,确保能完整克隆
高频 Canvas 渲染:用 OffscreenCanvas
如果 Worker 需要持续绘图(如视频帧处理、粒子动画),主线程创建 OffscreenCanvas 后移交控制权:
- 主线程:
const offscreen = canvas.transferControlToOffscreen() - 再通过
worker.postMessage(offscreen, [offscreen])把它转移过去 - Worker 中:
const ctx = offscreen.getContext('2d'),可直接绘图,无需操作 DOM - 绘制完成后,用
offscreen.transferToImageBitmap()传回图像数据供主线程显示
解耦响应逻辑:用 CustomEvent 分发结果
避免在主线程的 onmessage 里硬编码 DOM 操作。改用事件机制:
- 主线程监听
worker.onmessage,收到后派发new CustomEvent('data-processed', { detail: result }) - UI 模块、日志模块、动画控制器各自监听该事件,按需响应
- 这样 Worker 更新逻辑和 DOM 更新逻辑完全分离,便于测试和复用

















