WebWorker 是一种允许在主线程之外运行脚本的技术,可以用来处理耗时的计算而不阻塞主线程。
- 基本使用:
// main.js (主线程)
const worker = new Worker('worker.js')
// 发送消息给 Worker
worker.postMessage({ type: 'calculate', data: [1, 2, 3, 4] })
// 接收 Worker 返回的消息
worker.onmessage = function(e) {
console.log('从Worker收到结果:', e.data)
}
// 错误处理
worker.onerror = function(error) {
console.error('Worker错误:', error)
}
// worker.js (Worker线程)
self.onmessage = function(e) {
const { type, data } = e.data
if (type === 'calculate') {
const result = data.reduce((sum, num) => sum + num, 0)
self.postMessage(result)
}
}
- 使用Worker处理大量计算:
// main.js
const calculateBtn = document.getElementById('calculate')
const result = document.getElementById('result')
const worker = new Worker('worker.js')
calculateBtn.addEventListener('click', () => {
const numbers = Array(1000000).fill().map(() => Math.random())
worker.postMessage(numbers)
// UI不会被阻塞
result.textContent = '计算中...'
})
worker.onmessage = function(e) {
result.textContent = `计算结果: ${e.data}`
}
// worker.js
self.onmessage = function(e) {
const numbers = e.data
// 耗时计算
const sum = numbers.reduce((acc, curr) => acc + curr, 0)
const average = sum / numbers.length
self.postMessage(average)
}
- Worker中的数据传输:
// 传输普通数据
worker.postMessage({
type: 'process',
data: [1, 2, 3]
})
// 传输二进制数据(使用transferable objects)
const arrayBuffer = new ArrayBuffer(1024)
worker.postMessage(arrayBuffer, [arrayBuffer])
// 传输共享内存
const sharedArray = new SharedArrayBuffer(1024)
worker.postMessage(sharedArray)
- Worker池管理:
class WorkerPool {
constructor(workerScript, size) {
this.workers = []
this.queue = []
this.activeWorkers = new Map()
for (let i = 0; i < size; i++) {
const worker = new Worker(workerScript)
worker.onmessage = this.handleMessage.bind(this)
this.workers.push(worker)
}
}
execute(data) {
return new Promise((resolve, reject) => {
const task = { data, resolve, reject }
const availableWorker = this.workers.find(
worker => !this.activeWorkers.has(worker)
)
if (availableWorker) {
this.runTask(availableWorker, task)
} else {
this.queue.push(task)
}
})
}
runTask(worker, task) {
this.activeWorkers.set(worker, task)
worker.postMessage(task.data)
}
handleMessage(e) {
const worker = e.target
const task = this.activeWorkers.get(worker)
this.activeWorkers.delete(worker)
task.resolve(e.data)
if (this.queue.length > 0) {
this.runTask(worker, this.queue.shift())
}
}
terminate() {
this.workers.forEach(worker => worker.terminate())
this.workers = []
this.queue = []
this.activeWorkers.clear()
}
}
// 使用示例
const pool = new WorkerPool('worker.js', 4)
// 并发执行多个任务
Promise.all([
pool.execute([1, 2, 3]),
pool.execute([4, 5, 6]),
pool.execute([7, 8, 9])
]).then(results => {
console.log('所有任务完成:', results)
})
- 共享Worker:
// 创建共享Worker
const sharedWorker = new SharedWorker('shared-worker.js')
// 使用port通信
sharedWorker.port.start()
sharedWorker.port.postMessage('Hello')
sharedWorker.port.onmessage = function(e) {
console.log('收到消息:', e.data)
}
// shared-worker.js
const connections = new Set()
self.onconnect = function(e) {
const port = e.ports[0]
connections.add(port)
port.onmessage = function(e) {
// 广播消息给所有连接
for (const connection of connections) {
connection.postMessage(e.data)
}
}
port.start()
}
- Worker中的模块导入:
// worker.js
import { heavyCalculation } from './calculations.js'
self.onmessage = async function(e) {
const result = await heavyCalculation(e.data)
self.postMessage(result)
}
// main.js
const worker = new Worker('worker.js', {
type: 'module'
})
- Worker限制和注意事项:
- 不能访问DOM
- 不能使用window对象
- 有限的全局API访问
- 受同源策略限制
- 通信成本要考虑
- 内存占用需要管理
使用场景:
- 大量数据处理
- 复杂计算
- 图像处理
- 音视频处理
- 加密解密
- 实时数据分析
- 文件处理
最佳实践:
- 合理评估是否需要Worker
- 注意数据传输成本
- 使用Worker池管理并发
- 做好错误处理
- 及时清理不需要的Worker
- 考虑兼容性处理
WebWorker是一个强大的工具,可以显著提升web应用的性能和响应性,但需要合理使用并注意其限制。