JS Web Workers
学习多线程 · 难度:高级 · +15XP
JavaScript Web Workers 多线程编程
Web Workers 是浏览器提供的在后台线程中运行 JavaScript 的机制,允许在不阻塞主线程(UI 线程)的情况下执行耗时计算。JavaScript 通常在主线程单线程环境中运行,Web Workers 使得真正的并行处理成为可能,特别适用于数据处理、图像处理、加密计算等 CPU 密集型任务。
Web Worker 核心概念
- Worker 运行在独立线程中,无法访问 DOM、window 对象
- 主线程和 Worker 之间通过
postMessage发送消息通信 - 通过
onmessage事件接收消息 - 数据传输默认使用结构化克隆,也可以使用
Transferable对象
创建和使用 Worker
| API | 说明 | 使用位置 |
|---|---|---|
new Worker(url) | 创建 Worker 实例 | 主线程 |
worker.postMessage(data) | 向 Worker 发送数据 | 主线程 |
worker.onmessage | 接收 Worker 返回的数据 | 主线程 |
worker.onerror | Worker 错误处理 | 主线程 |
worker.terminate() | 立即终止 Worker | 主线程 |
self.postMessage(data) | 向主线程发送数据 | Worker 内部 |
self.onmessage | 接收主线程数据 | Worker 内部 |
// 主线程代码 (main.js)
// 创建 Worker
const worker = new Worker("worker.js");
// 向 Worker 发送数据
worker.postMessage({ type: "calculate", data: 1000000 });
// 接收 Worker 返回的数据
worker.onmessage = (event) => {
console.log("主线程收到结果:", event.data);
// event.data 是 Worker 发送过来的计算结果
};
// 错误处理
worker.onerror = (error) => {
console.error("Worker 错误:", error.message);
};
// 任务完成后终止 Worker(释放资源)
// worker.terminate();
Worker 脚本实现
// worker.js — Worker 线程代码
// self 代表 Worker 的全局作用域(相当于主线程的 window)
// 接收主线程消息
self.onmessage = (event) => {
const { type, data } = event.data;
switch (type) {
case "calculate":
// 执行耗时计算
const result = heavyCalculation(data);
// 将结果发送回主线程
self.postMessage({ type: "result", value: result });
break;
case "fibonacci":
const fibResult = fibonacci(data);
self.postMessage({ type: "result", value: fibResult });
break;
default:
self.postMessage({ type: "error", message: "未知任务类型" });
}
};
function heavyCalculation(n) {
let sum = 0;
for (let i = 0; i < n; i++) {
sum += Math.sqrt(i) * Math.sin(i);
}
return sum;
}
function fibonacci(n) {
if (n <= 1) return n;
let a = 0, b = 1;
for (let i = 2; i <= n; i++) {
[a, b] = [b, a + b];
}
return b;
}
高级用法:SharedWorker 与 Transferable
// Transferable 对象:零拷贝传输大数据
const buffer = new ArrayBuffer(1024 * 1024 * 10); // 10MB
// 使用 transferList 转移所有权,比结构化克隆快得多
worker.postMessage({ buffer }, [buffer]);
// 传输后主线程不能再使用该 buffer!
// SharedWorker:多个页面共享同一个 Worker
// const sharedWorker = new SharedWorker("shared-worker.js");
// sharedWorker.port.start();
// sharedWorker.port.postMessage(data);
// sharedWorker.port.onmessage = (e) => console.log(e.data);
// 内联 Worker(使用 Blob URL,避免单独文件)
const workerCode =
self.onmessage = (e) => {
const result = e.data * 2;
self.postMessage(result);
};
;
const blob = new Blob([workerCode], { type: "application/javascript" });
const blobUrl = URL.createObjectURL(blob);
const inlineWorker = new Worker(blobUrl);
URL.revokeObjectURL(blobUrl); // 释放 Blob URL