跳到主要内容

线程间通信

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 对象提供的原子操作协调读写;