面试回答: Web Worker 是浏览器提供的后台线程能力,适合把排序、加密、图像处理等 CPU 密集型任务移出渲染主线程。Worker 不能直接操作 DOM,主线程与 Worker 通过
postMessage通信,数据默认经过结构化克隆;传输大型ArrayBuffer时可以使用 Transferable 转移所有权以减少复制开销。Dedicated Worker 服务单个页面,Shared Worker 可被多个同源页面共享,Service Worker 则是带独立生命周期的网络代理,主要用于离线缓存和请求拦截,不能把三者当成同一种用途。
页面的 JavaScript、用户事件和大部分渲染工作共享主线程。一个持续数百毫秒的计算任务会占住调用栈,导致点击无法响应、动画掉帧和页面卡顿。
事件循环只能安排任务的先后顺序,不能让正在执行的长任务自动并行。Web Worker 提供独立线程,可以把纯计算迁移到后台,让主线程继续响应用户和渲染页面。
Worker 并不会让单个算法天然变快。它的主要价值是隔离主线程阻塞;如果任务很小,线程启动、数据复制和消息通信的成本反而可能更高。
| 类型 | 使用范围 | 主要用途 | 生命周期 |
|---|---|---|---|
| Dedicated Worker | 创建它的页面或脚本 | 单页面 CPU 密集型计算 | 通常随所属页面结束,应用也应主动终止 |
| Shared Worker | 多个同源页面、标签页或 iframe | 跨页面共享后台状态或复用连接 | 只要仍有页面连接,就可能继续存活 |
| Service Worker | 受其作用域控制的页面 | 请求拦截、离线缓存、推送和 PWA | 由浏览器按事件唤醒和终止,不依附某个页面 |
日常所说的 new Worker() 指的是 Dedicated Worker。
每次创建都会产生一个专用 Worker 实例,适合大数组处理、文件哈希、图像像素计算、压缩和加解密等任务。
多个同源页面可以连接到同一个 Shared Worker,并通过各自的 MessagePort 通信。它适合跨标签页共享状态或复用一个后台连接,但兼容性、调试和连接生命周期都比 Dedicated Worker 更复杂。
Service Worker 位于页面与网络之间,能够监听 fetch 事件并决定从网络还是缓存返回响应。它不是常驻的计算线程,也不应该用来执行任意长时间 CPU 任务。
Worker 运行在独立的 WorkerGlobalScope 中,不是 window。
可以使用的常见能力包括:
fetch、XMLHttpRequest 等网络请求;setTimeout、setInterval;URL、Blob、ArrayBuffer 等数据处理 API;WebAssembly;OffscreenCanvas 等适合后台处理的 API。主要限制包括:
window、document 和页面 DOM;localStorage;如果后台计算需要影响页面,应把结果发送给主线程,再由主线程修改 DOM。
主线程创建 Worker,并通过消息传递任务:
Worker 脚本接收任务并返回结果:
实际项目中还需要为消息设计任务 ID、成功结果和错误结果,否则多个并发任务很难正确匹配响应。
postMessage 默认使用结构化克隆算法传递数据。接收方拿到的是独立副本,而不是可以被两个线程同时修改的普通对象引用。
结构化克隆支持对象、数组、Map、Set、Blob、ArrayBuffer 等类型,但函数和 DOM 节点不能直接传递。
大型二进制数据如果直接克隆,可能产生明显的复制成本。对于 ArrayBuffer、MessagePort、ImageBitmap 等可转移对象,可以把底层资源的所有权直接转交给 Worker:
转移完成后,原线程中的 buffer 会被分离,不能继续读写。这不是两个线程共享同一份可变数据,而是一次所有权移交。
SharedArrayBuffer 才允许多个线程访问同一块内存,通常需要配合 Atomics 做同步,并要求页面满足跨源隔离等安全条件。除非确实需要高性能共享内存,否则优先使用消息传递,模型更简单也更安全。
Worker 不再使用时应主动终止:
Worker 内部也可以调用:
在单页应用中,如果每次进入页面都创建 Worker,却没有在离开页面时终止,后台线程及其持有的数据可能不断累积。创建 Worker 的模块或组件应该同时负责:
terminate();适合:
不适合:
判断标准不是“代码是否异步”,而是它是否长时间占用主线程,以及任务输入输出是否适合通过消息传递。
它能提供并行计算线程,但不会改变页面主线程仍然单线程执行 JavaScript 和更新 DOM 的事实。多个线程通过消息而不是共享普通对象协作。
如果多个线程可以同时读写页面结构,就需要复杂的锁和一致性机制。浏览器把 DOM 修改集中在主线程,换取更清晰的执行与渲染模型。
不是。线程会消耗内存和调度资源,任务拆分与通信也有成本。Worker 数量应根据任务特征和设备并发能力控制,不能无限创建。
Worker 脚本加载受来源、CORS、内容安全策略和 Worker 类型影响。工程中通常由构建工具产出同源 Worker 资源,不应把“配置一个 CORS 响应头”当成适用于所有 Worker 的通用结论。