Web Worker 与主线程的交互完全依赖于消息传递机制—— 两者无法直接共享内存或访问对方的变量 / 对象,必须通过显式的 “发送消息” 和 “接收消息” 完成通信。这种交互是异步的,不会阻塞对方线程的执行。
核心交互方式
通过两个核心 API 实现:
postMessage(data):发送消息(主线程和 Worker 都可调用)。onmessage事件:监听并接收消息(主线程和 Worker 都可注册)。
详细交互流程
1. 主线程 → Worker 发送消息
主线程创建 Worker 后,通过worker.postMessage(data)向 Worker 发送数据;Worker 通过self.onmessage监听并处理消息。
示例代码:
javascript
运行
// 主线程(main.js)
const worker = new Worker('worker.js');
// 发送消息给 Worker(数据可以是字符串、对象、数组等可序列化类型)
worker.postMessage({ type: 'task', content: '计算 1 到 100000 的和' });
// Worker(worker.js)
// 监听主线程消息
self.onmessage = (event) => {
const { type, content } = event.data; // event.data 是主线程发送的数据
console.log('Worker 收到消息:', content);
// 处理任务(例如计算总和)
let sum = 0;
for (let i = 1; i <= 100000; i++) {
sum += i;
}
// 向主线程返回结果(见步骤 2)
self.postMessage({ result: sum });
};
2. Worker → 主线程返回消息
Worker 处理完任务后,通过self.postMessage(data)向主线程发送结果;主线程通过worker.onmessage监听并接收结果。
示例代码(接上面):
javascript
运行
// 主线程(main.js)
// 监听 Worker 返回的消息
worker.onmessage = (event) => {
const { result } = event.data; // event.data 是 Worker 发送的结果
console.log('主线程收到结果:', result); // 输出:5000050000
};
数据传递的底层机制:结构化克隆
主线程与 Worker 之间传递的数据并非 “共享内存”,而是通过结构化克隆算法(Structured Cloning Algorithm)进行复制:
- 发送方的
data会被序列化(转为字节流),传递到接收方后再反序列化为新的对象。 - 这意味着:发送方和接收方的
data是两个独立的副本,修改一方的数据不会影响另一方。
支持传递的数据类型
大部分常见数据类型都支持结构化克隆,包括:
- 基本类型(字符串、数字、布尔值、null、undefined);
- 对象(普通对象、数组、Date、RegExp);
- 二进制数据(ArrayBuffer、TypedArray、DataView);
- Map、Set 等。
不支持传递的数据类型
以下类型无法通过postMessage传递(会报错):
- DOM 元素(如
document、div节点); - 函数(
function); - 错误对象(
Error); - 某些特殊对象(如
window、self、XMLHttpRequest实例等)。
优化:可转移对象(Transferable Objects)
对于二进制数据(如ArrayBuffer),如果通过结构化克隆复制,可能因数据量大导致性能损耗。此时可使用可转移对象,将数据的 “所有权” 从发送方转移到接收方(发送方会失去对该数据的访问权),避免复制。
使用方式:在postMessage第二个参数中指定转移的对象:
javascript
运行
// 主线程
const buffer = new ArrayBuffer(1024 * 1024); // 1MB 二进制数据
// 第二个参数是转移对象数组(仅支持 ArrayBuffer 等特定类型)
worker.postMessage({ buffer }, [buffer]);
// 此时主线程的 buffer 已失效,访问会报错
// Worker 中可正常使用 buffer
self.onmessage = (e) => {
const { buffer } = e.data; // 获得所有权,可正常操作
};
错误处理
如果 Worker 内部发生错误,会触发主线程的onerror事件:
javascript
运行
// 主线程监听 Worker 错误
worker.onerror = (error) => {
console.error(`Worker 错误:${error.message},行号:${error.lineno}`);
worker.terminate(); // 可选择终止 Worker
};
终止交互
- 主线程可通过
worker.terminate()强制终止 Worker(Worker 线程会立即停止,无法再通信)。 - Worker 可通过
self.close()主动关闭自身(关闭后无法再发送消息)。
总结
Web Worker 与主线程的交互核心是 **“消息传递 + 结构化克隆”**:
- 双方通过
postMessage发送消息,onmessage接收消息; - 数据通过复制传递(非共享),支持大部分类型,但不支持 DOM、函数等;
- 二进制数据可通过 “转移所有权” 优化性能;
- 交互是异步的,确保主线程不被阻塞。
这种机制既保证了线程隔离的安全性,又实现了灵活的任务协作。

下方查看历史文章

【前端每日一题】前端分块是如何分的,根据什么分的,分的是chunk还是依赖
3530

被折叠的 条评论
为什么被折叠?



