Web Workers

Web Worker 的类型、postMessage 通信、Transferable Objects 与使用限制。

#tech / dev / frontend #resource / browser #type / concept #status / growing

[!info] related notes

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

支持转移的类型:ArrayBufferMessagePortImageBitmapOffscreenCanvasReadableStream/WritableStream/TransformStream

SharedArrayBuffer 允许多个线程共享同一块内存(需配合 Atomics 原子操作避免竞态条件)。

限制

Worker 不能访问:

  • document(DOM)
  • window 对象
  • parent 对象
  • DOM 元素

Worker 可以访问:

  • navigator
  • location(只读)
  • XMLHttpRequest / fetch
  • setTimeout / setInterval
  • IndexedDB
  • WebSocket
  • self(Worker 全局对象)

错误处理

主线程通过 worker.onerror 监听,包含 messagefilenamelineno。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 代理网络请求,实现离线缓存。

创建于 2026/5/27 更新于 2026/5/27