浏览器 Web Workers
Web Worker 在页面主线程之外提供独立 JavaScript 执行环境,通过消息传递、structured clone、Transferable 或 SharedArrayBuffer 与主线程协作,适合 CPU 密集工作而不是普通网络等待。
[!info] related notes
- 所属 MOC: 浏览器 JS MOC, JavaScript MOC
- 并发背景: JavaScript 中的进程、线程与协程, 浏览器 Event Loop
- Node 对比: Node.js Worker Threads
- Service Worker: Service Worker 与 Cache API
浏览器 Web Workers
一句话定义
Web Worker 让浏览器在页面主线程之外运行独立 JavaScript 执行环境。
核心价值是把会长期占用 CPU 的工作移出 UI 主线程。
为什么需要 Worker
主线程同时承担 JavaScript、DOM event、style/layout、paint 和用户交互。
如果大计算长期占住主线程,就会让 input/render 被推迟并产生卡顿。
Worker 可以把这类 CPU 工作移到独立执行环境。
Worker 与 async/await 的边界
Promise / async/await 主要解决异步控制流。
例如等待 fetch 时,并不需要主线程持续做 CPU 计算。
Worker 解决的是:真正有 CPU 工作需要并行执行。
典型场景:
- 大量 JSON/二进制解析;
- 图像/音视频处理;
- 压缩/加密;
- 大规模计算;
- 数据转换。
Dedicated Worker
Dedicated Worker 由一个 owner 页面创建和使用。
主线程通过 postMessage 发送任务,Worker 计算后再通过 message 返回结果。
Shared Worker
Shared Worker 可以被多个符合条件的 browsing context 共享。
它更适合跨 tab/context 的共享后台执行或通信,但生命周期和浏览器支持边界比 Dedicated Worker 更复杂。
Service Worker 不是普通计算 Worker
Service Worker 的主要职责是 network interception、cache/offline、background event 与 push 等。
它不是页面 CPU 计算 Worker 的增强版。
Worker 中没有 DOM
Worker 不能直接操作 document 或页面 DOM。
如果计算结果需要更新 UI,必须把结果发送回主线程,再由主线程更新 DOM。
这是重要 ownership boundary。
postMessage 与 Structured Clone
默认消息传递会使用 structured clone 语义,把可克隆数据复制到另一执行环境。
大对象复制本身可能很贵,所以 Worker 不等于“把代码搬过去就一定更快”。
Transferable Objects
某些底层 buffer 可以 transfer ownership,而不是复制。
例如 ArrayBuffer 转移到 Worker 后,ownership 转给另一侧,原一侧不能再按原方式使用它。
适合大二进制数据。
SharedArrayBuffer
需要真正共享内存时可以使用 SharedArrayBuffer + Atomics。
但这会引入 synchronization、race condition、memory ordering 与安全隔离要求。
不要为了少一次 copy 就轻易使用共享内存。
Worker 也有自己的 Event Loop
Worker 是独立执行环境,也有自己的 task/microtask 调度。
它不是简单“开一个函数线程”。
主线程与 Worker 之间的通信本身也是异步事件。
Worker 的成本
创建 Worker 有 startup、script loading、memory、message serialization/transfer 与 coordination 成本。
很小的计算搬到 Worker 可能反而更慢。
什么时候不用 Worker
- 普通 fetch / I/O 等待;
- 很短的小计算;
- 必须频繁直接操作 DOM;
- 每次传输的数据巨大,而计算本身很轻;
- 无法明确管理 worker lifecycle。
生命周期
需要考虑创建时机、复用、error handling、页面销毁时 terminate,以及 pending request 如何取消或忽略。
Worker 也是资源,不应该无限创建。
学习检查
- Worker 解决的问题与 async/await 有什么根本差异?
- 为什么 Worker 不能直接操作 DOM?
- postMessage 默认为什么可能有大对象复制成本?
- Transferable 与 structured clone 有什么差异?
- SharedArrayBuffer 为什么比普通 postMessage 复杂很多?
- Service Worker 与 Dedicated Worker 的主要职责差异是什么?
- 给“解析 100MB 文件”和“等待 REST API”两个任务判断是否需要 Worker,并解释理由。