news 2026/3/19 20:13:50

工作者线程 postMessage() 方法参数详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
工作者线程 postMessage() 方法参数详解

postMessage() 方法参数详解


postMessage()方法有两种形式:


1. Window.postMessage()

javascript

otherWindow.postMessage(message, targetOrigin, [transfer]);

2. Worker.postMessage() 和 MessagePort.postMessage()

javascript

worker.postMessage(message, [transfer]); // 或 port.postMessage(message, [transfer]);

参数说明

第一个参数:message(必需)

  • 要发送的数据
  • 可以是任何可序列化的 JavaScript 对象
  • 浏览器会使用结构化克隆算法来复制数据
  • 可以包含循环引用

第二个参数:targetOrigin(仅 Window.postMessage 需要)

  • 指定目标窗口的源(协议+主机+端口号)
  • 用于安全检查,防止消息发送到错误的域
  • 可以设置为 "*" 表示不限制目标源(不推荐)

  • targetOrigin

    • 指定哪些窗口能接收消息

    • 可以是具体的域名(如 "https://example.com")或通配符:

      • "*":发送到任何窗口(不安全)

      • "/":发送到同源窗口

第三个参数:transfer(可选)

  • 一个数组,包含需要转移所有权的对象
  • 主要用于 Transferable 对象,如 ArrayBuffer、MessagePort 等
  • 转移后,发送方将失去对这些对象的访问权限

可转移对象类型

// 1. ArrayBuffer const buffer = new ArrayBuffer(1024); window.postMessage(buffer, '*', [buffer]); // buffer 现在在发送方变为不可用 // 2. MessagePort const channel = new MessageChannel(); window.postMessage('message', '*', [channel.port2]); // 3. ImageBitmap const imageBitmap = await createImageBitmap(image); window.postMessage({ image: imageBitmap }, '*', [imageBitmap]); // 4. OffscreenCanvas const offscreen = new OffscreenCanvas(256, 256); window.postMessage({ canvas: offscreen }, '*', [offscreen]);

可转移对象 vs 结构化克隆

结构化克隆(默认行为)

const worker = new Worker('./worker.js'); const buffer = new ArrayBuffer(8); console.log('发送前 buffer 大小:', buffer.byteLength); // 8 // 结构化克隆 - 数据被复制 worker.postMessage(buffer); console.log('发送后 buffer 大小:', buffer.byteLength); // 8 (仍然可以访问)

可转移对象

const worker = new Worker('./worker.js'); const buffer = new ArrayBuffer(8); console.log('发送前 buffer 大小:', buffer.byteLength); // 8 // 转移对象 - 所有权转移给 worker worker.postMessage(buffer, [buffer]); console.log('发送后 buffer 大小:', buffer.byteLength); // 0 (失去访问权限)

使用示例

基本使用

javascript

// 父窗口发送消息 const iframe = document.querySelector('iframe'); const buffer = new ArrayBuffer(1024); // 转移 buffer 所有权 iframe.contentWindow.postMessage( { type: 'data', buffer }, 'https://example.com', [buffer] // buffer 被转移 ); console.log(buffer.byteLength); // 0 - 已不可用

多个可转移对象

javascript

const buffer1 = new ArrayBuffer(256); const buffer2 = new ArrayBuffer(512); const channel = new MessageChannel(); parentWindow.postMessage( { buffers: [buffer1, buffer2], port: channel.port1 }, '*', [buffer1, buffer2, channel.port1] // 转移所有对象 );

重要注意事项


1.所有权转移是永久性的

javascript

const buffer = new ArrayBuffer(1024); postMessage(buffer, '*', [buffer]); // 错误!buffer 已转移,不能再使用 const view = new Uint8Array(buffer); // TypeError

2.只能转移特定的对象类型

尝试转移不可转移的对象会抛出错误:

javascript

const obj = { name: 'test' }; postMessage(obj, '*', [obj]); // TypeError: Value at index 0 is not transferable

3.性能优势

转移比复制更高效,特别对于大型数据:

javascript

// 复制方式(占用双倍内存) const largeBuffer = new ArrayBuffer(100 * 1024 * 1024); // 100MB postMessage({ data: largeBuffer }, '*'); // 完整复制 // 转移方式(零拷贝) postMessage(largeBuffer, '*', [largeBuffer]); // 仅转移所有权

4.接收方处理

javascript

// 接收方 window.addEventListener('message', (event) => { if (event.data.buffer) { // buffer 的所有权现在属于这个上下文 const view = new Uint8Array(event.data.buffer); // 使用 view... // 可以选择再转移回去 event.source.postMessage('done', '*', [event.data.buffer]); } });

实际应用场景


高性能图像处理

javascript

// 主线程 → Worker const offscreen = new OffscreenCanvas(800, 600); const bitmap = offscreen.getContext('2d').getImageData(0, 0, 800, 600); worker.postMessage({ bitmap }, '*', [bitmap]);

音频数据处理

javascript

// 处理音频流 const audioBuffer = audioContext.createBuffer(2, 44100, 44100); worker.postMessage({ audio: audioBuffer }, '*', [audioBuffer]);

WebGL纹理共享

javascript

// 共享纹理数据 const gl = canvas.getContext('webgl'); const texture = gl.createTexture(); // ...设置纹理数据 offscreenCanvas.transferToImageBitmap(); // 转移到 Worker 进行处理

浏览器兼容性

  • 所有现代浏览器都支持基本的postMessage()

  • 可转移对象支持:

    • ArrayBuffer: Chrome 13+, Firefox 18+, Safari 6+

    • MessagePort: Chrome 59+, Firefox 59+, Safari 11.1+

    • ImageBitmap: Chrome 52+, Firefox 51+, Safari 11.1+


最佳实践

  1. 始终指定具体的 targetOrigin,避免使用"*"

  2. 验证消息来源


javascript

window.addEventListener('message', (event) => { if (event.origin !== 'https://trusted-domain.com') return; // 处理消息 });

  1. 及时释放资源:转移后主动清理引用

  2. 错误处理:处理转移失败的情况


transfer参数是实现高性能跨线程/跨文档通信的关键特性,特别适用于处理大型二进制数据。


关键要点总结

  1. 结构化克隆:默认情况下,postMessage 会对传输的数据进行深拷贝,发送方保留数据副本。

  2. 可转移对象:通过 transfer 数组指定的对象会转移所有权,发送方失去访问权限,接收方获得所有权。

  3. 性能优势:对于大型数据(如 ArrayBuffer),使用可转移对象可以显著提高性能,避免不必要的数据复制。

  4. 适用对象:常见的可转移对象包括 ArrayBuffer、MessagePort、ImageBitmap 等。

  5. 使用场景:适用于需要在主线程和 worker 之间高效传输大量数据的情况,例如图像处理、音频数据处理等。


这种方式特别适合需要高性能数据传输的场景,因为它避免了复制大型数据结构的开销。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/15 21:51:44

企业级IP地址管理系统的5个实战案例

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个企业级IP地址管理系统案例展示页面,包含5个典型应用场景:1. 中小企业办公网络IP管理 2. 学校机房IP分配 3. 云计算环境弹性IP管理 4. 物联网设备IP自…

作者头像 李华
网站建设 2026/3/15 21:51:57

BERT原论文读后感

读后感 — BERT: Pre-training of Deep Bidirectional Transformers阅读 BERT 原论文让我对现代预训练语言模型的设计哲学和工程实现有了更深刻的理解,尤其是[CLS] 标记的设计意图和 Fine-tuning 的通用范式 部分。在传统的深度模型中,如何将预训练得到的…

作者头像 李华
网站建设 2026/3/15 7:34:09

企业级Oracle RAC集群实战安装指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个Oracle RAC集群部署模拟器,模拟2节点RAC环境的安装过程。要求:1) 可视化展示共享存储配置(ASM) 2) 网络拓扑图展示(public/private网络) 3) 分步演示…

作者头像 李华
网站建设 2026/3/15 11:49:09

三分钟构建智能AI集群:Exo资源配额自动分配全解析

三分钟构建智能AI集群:Exo资源配额自动分配全解析 【免费下载链接】exo Run your own AI cluster at home with everyday devices 📱💻 🖥️⌚ 项目地址: https://gitcode.com/GitHub_Trending/exo8/exo 还在为家中闲置设备…

作者头像 李华
网站建设 2026/3/15 1:21:48

国产出图神器!行政边界一键填充配色、秒出专业图,附完整教程

告别繁琐,三步出图!从加载数据、自定义配色到添加指北针、比例尺等专业元素,Bigemap Pro助你轻松完成一张规范、美观的行政边界图。支持直接打印,或导出高清PDF无缝嵌入汇报PPT。一、行政边界图制作全流程详解 1. 数据加载与边界提…

作者头像 李华
网站建设 2026/3/15 11:52:30

测试精粹:资深专家的十项实战心法

测试专家的价值与时代意义 在数字化浪潮席卷全球的今天,软件质量已成为企业竞争力的核心要素。作为软件测试从业者,我们不仅是缺陷的发现者,更是质量文化的推动者。测试专家通过多年的项目历练,总结出宝贵的经验教训,…

作者头像 李华