439 字
2 分钟
10 · Web Workers 与多线程
单线程的墙
前面说过 JS 单线程,重计算(如大数组排序、图像/音频处理、加密)会卡住主线程,UI 冻结。Web Worker 提供了真正的多线程:把这类活丢到后台线程跑。
Worker 基本用法
const worker = new Worker("worker.js");worker.postMessage({ type: "calc", data: bigArray });worker.onmessage = (e) => console.log("结果", e.data);
// worker.jsself.onmessage = (e) => { const result = heavyCompute(e.data.data); self.postMessage(result);};- 主线程与 Worker 不共享内存,通过
postMessage传数据。 - 数据用结构化克隆传递(默认拷贝;大对象可用
Transferable转移所有权,零拷贝)。
适用场景
- 大数组/矩阵运算、排序、压缩。
- 图像处理(canvas 像素级操作)。
- 音视频编解码、加密解密。
- 解析大 JSON / 文档。
不适合:直接操作 DOM(Worker 里没有 document)、频繁小消息(通信也有开销)。
现代封装:Comlink
手写 postMessage 像在写 RPC,繁琐。Comlink 把 Worker 暴露的对象变成可 await 的远程对象:
import * as Comlink from "comlink";Comlink.expose({ heavyCompute });
// main.jsconst api = Comlink.wrap(new Worker("worker.js"));await api.heavyCompute(data); // 像调本地函数限制与权衡
- Worker 有启动/通信成本,轻量计算不值得搬。
- 复杂共享状态可用
SharedWorker(多标签页共享)或SharedArrayBuffer(需COOP/COEP 头)。 - 模块 Worker:
new Worker(url, { type: "module" })支持 ESM。
小结
- Web Worker 把重计算移出主线程,保 UI 流畅。
- 通过
postMessage通信,数据走结构化克隆(大对象用 Transferable)。 - 适合重计算,不适合操作 DOM 或超高频小消息。
- Comlink 让 Worker 调用像本地异步函数。
练习
- 写一个 Worker 做”大数组排序”,对比放主线程时页面是否冻结。
- 用
Transferable传递一个大ArrayBuffer,体会零拷贝。 - 用 Comlink 重构上面的 Worker 调用,对比代码可读性。
10 · Web Workers 与多线程
http://117.72.32.87/blog/posts/browser-roadmap-10-web-workers/