Web Workers
Web Worker 的类型、postMessage 通信、Transferable Objects 与使用限制。
[!info] related notes
- 所属 MOC: 前端基础 MOC
- 相关概念: event-loop, [[dom]]
Web Workers
定义
Web Worker 是浏览器提供的多线程机制,允许在后台线程中运行 JavaScript,不阻塞主线程(UI 线程)。Worker 与主线程通过消息传递通信,不能直接访问 DOM。
三种类型
| 类型 | 作用域 | 实例数 | 适用场景 |
|---|---|---|---|
| Dedicated Worker | 单独的页面 | 一个页面一个实例 | CPU 密集计算 |
| Shared Worker | 跨页面共享 | 同源多个页面共享一个实例 | 跨标签页通信 |
| Service Worker | 网络代理 | 一个域一个实例 | 离线缓存、推送通知 |
Dedicated Worker
创建 Worker
// main.js
const worker = new Worker('worker.js')
// 发送消息
worker.postMessage({ type: 'calculate', data: [1, 2, 3, 4, 5] })
// 接收消息
worker.onmessage = (event) => {
console.log('结果:', event.data)
}
// 错误处理
worker.onerror = (error) => {
console.error('Worker 错误:', error)
}
// 终止 Worker
worker.terminate()
Worker 文件
// worker.js
self.onmessage = (event) => {
const { type, data } = event.data
if (type === 'calculate') {
const result = data.reduce((sum, n) => sum + n, 0)
self.postMessage(result)
}
}
使用模块语法
// 创建时指定为模块
const worker = new Worker('worker.js', { type: 'module' })
// worker.js 中可以使用 import
import { heavyCalculation } from './utils.js'
self.onmessage = (e) => {
self.postMessage(heavyCalculation(e.data))
}
Shared Worker
多个同源页面共享同一个实例,通过 port 通信。适合跨标签页数据同步。使用 new SharedWorker('worker.js') 创建,通过 worker.port.start() 启用消息通道。
Service Worker
充当网络请求的代理,拦截请求、缓存资源、实现离线访问。生命周期:install(预缓存)→ activate(清理旧缓存)→ fetch(拦截请求)。通过 navigator.serviceWorker.register('/sw.js') 注册,作用域由文件位置决定。
postMessage 通信
主线程和 Worker 之间通过 postMessage 传递数据。
// 基本用法
worker.postMessage(data)
worker.onmessage = (e) => { /* e.data */ }
// 双向通信模式
worker.onmessage = (e) => {
if (e.data.type === 'result') {
console.log('计算结果:', e.data.value)
}
}
数据拷贝 vs 转移
默认情况下,postMessage 会结构化克隆数据(深拷贝),大数据量时可能很慢。
Transferable Objects
可以转移对象的所有权(而非拷贝),速度极快,但转移后原对象不可用。
// 创建一个 ArrayBuffer
const buffer = new ArrayBuffer(1024 * 1024) // 1MB
// 转移所有权(不是拷贝)
worker.postMessage(buffer, [buffer])
// 转移后,buffer 在主线程不可用
console.log(buffer.byteLength) // 0
支持转移的类型:ArrayBuffer、MessagePort、ImageBitmap、OffscreenCanvas、ReadableStream/WritableStream/TransformStream。
SharedArrayBuffer 允许多个线程共享同一块内存(需配合 Atomics 原子操作避免竞态条件)。
限制
Worker 不能访问:
document(DOM)window对象parent对象- DOM 元素
Worker 可以访问:
navigatorlocation(只读)XMLHttpRequest/fetchsetTimeout/setIntervalIndexedDBWebSocketself(Worker 全局对象)
错误处理
主线程通过 worker.onerror 监听,包含 message、filename、lineno。Worker 内部通过 self.onerror 捕获错误并上报。
实际应用场景
- 大数据排序、搜索、过滤
- 图片处理(像素操作)
- 加密解密计算
- 语法高亮、Markdown 解析
- 离线缓存和资源预加载(Service Worker)
- 跨标签页数据同步(Shared Worker)
边界
- Worker 线程不能操作 DOM,需要通过消息传递让主线程更新 UI
- 创建 Worker 有开销(加载文件、初始化),不适合频繁创建销毁
- Worker 中的错误不会冒泡到主线程,需要监听
onerror - Service Worker 的作用域由其文件位置决定,不能超出自身路径
importScripts()是同步加载,type: 'module'的 Worker 可以用import异步加载
一句话记忆法
Worker 在后台线程跑 JS,不阻塞 UI;用 postMessage 通信,大数据用 Transferable Objects 转移所有权;Service Worker 代理网络请求,实现离线缓存。
Related notes
- 前端基础 MOC
- event-loop
- [[dom]]