Web Worker 是什么?如何使用?有什么限制?

Web Worker

JavaScript 是单线程的,Web Worker 允许在后台线程中运行 JS,不阻塞主线程。

基本使用

主线程:

// 创建 Worker
const worker = new Worker('worker.js')

// 发送数据
worker.postMessage({ command: 'calculate', data: [1, 2, 3] })

// 接收 Worker 返回的数据
worker.onmessage = (e) => {
  console.log('结果:', e.data)
}

// 错误处理
worker.onerror = (e) => {
  console.error('Worker error:', e.message)
}

// 终止
worker.terminate()

Worker 线程(worker.js):

// 接收主线程数据
self.onmessage = (e) => {
  const { command, data } = e.data
  
  if (command === 'calculate') {
    const result = heavyComputation(data)
    // 发送结果回主线程
    self.postMessage(result)
  }
}

function heavyComputation(data) {
  // 耗时计算...
  return data.reduce((sum, n) => sum + n, 0)
}

使用场景

  1. 大量计算:图像处理、加密、排序
  2. 数据处理:解析大 JSON、CSV
  3. 后台轮询:实时数据获取
  4. 离线缓存处理
// 内联 Worker(不需要单独文件)
const workerCode = `
  self.onmessage = (e) => {
    const result = e.data * 2
    self.postMessage(result)
  }
`
const blob = new Blob([workerCode], { type: 'application/javascript' })
const worker = new Worker(URL.createObjectURL(blob))

SharedWorker(多标签页共享)

// 多个标签页共享同一个 Worker
const sharedWorker = new SharedWorker('shared-worker.js')
sharedWorker.port.onmessage = (e) => console.log(e.data)
sharedWorker.port.postMessage('hello')

Worker 的限制

特性 支持
DOM 操作 ❌
window 对象 ❌(用 self)
XMLHttpRequest ✅
fetch ✅
WebSocket ✅
IndexedDB ✅
setTimeout/setInterval ✅
importScripts() ✅(引入其他脚本)
console.log ✅
location/navigator ✅(只读)

Transferable Objects(零拷贝传输)

// ArrayBuffer 可以零拷贝转移(原线程不能再使用)
const buffer = new ArrayBuffer(1024 * 1024)
worker.postMessage(buffer, [buffer]) // 第二个参数是 transfer list
console.log(buffer.byteLength) // 0(已转移)

性能注意

实际应用示例

// 大数据排序
worker.postMessage({ data: hugeArray })
// 主线程仍然流畅

// 实时图像处理
const canvas = document.querySelector('canvas')
const imageData = canvas.getContext('2d').getImageData(0, 0, w, h)
worker.postMessage(imageData, [imageData.data.buffer])
// Worker 处理后返回新的 imageData

主线程替代方案

对于不需要真正多线程的场景,可以用以下方式避免阻塞:

推荐场景

同分类其他题目