线程间通信
postMessage 如何双向通信?
// main.js
const worker = new Worker("./worker.js");
worker.onmessage = ({ data }) => console.log(data);
worker.postMessage(5);
// worker.js
self.onmessage = ({ data }) => {
self.postMessage(`${data} in worker.js`);
};
MessageChannel 如何使用?
- 用途: 提供一对
MessagePort, 可实现主线程与线程、或线程之间的点对点通信;
const channel = new MessageChannel();
const worker = new Worker("./worker.js");
worker.postMessage(null, [channel.port1]); // 把一个端口转移给线程
channel.port2.onmessage = ({ data }) => console.log(data);
channel.port2.postMessage(5);
BroadcastChannel 如何使用?
- 用途: 同源上下文之间广播消息, 无需显式建立连接;
const channel = new BroadcastChannel("worker_channel");
channel.onmessage = ({ data }) => console.log(`heard ${data}`);
channel.postMessage("foo");
消息是怎样被传递的?
- 结构化克隆算法:
postMessage传递对象时按该算法生成副本; - 适用类型: 基本类型、普通对象、数组、
Map、Set、Date、RegExp等可序列化类型; - 性能: 克隆大对象开销明显, 应避免传递过大的结构;
- 转移所有权: 通过
transferList把对象所有权移交对方, 原上下文失去引用;
const arrayBuffer = new ArrayBuffer(32);
worker.postMessage(arrayBuffer, [arrayBuffer]);
arrayBuffer.byteLength; // 0; 已转移
SharedArrayBuffer 如何共享内存?
- 机制: 多个上下文引用同一块内存, 不做克隆;
- 风险: 会出现资源争用;
- 同步: 用
Atomics对象提供的原子操作协调读写;