news 2026/4/23 14:17:17

工作者线程 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/4/17 21:23:15

C++ STL string 用法详解与示例

目录 引言 1. 字符串的创建和初始化 2. 字符串基本操作 2.1 获取字符串信息 2.2 访问和修改字符 3. 字符串修改操作 3.1 追加字符串 3.2 插入字符串 3.3 删除字串内容 3.4 替换字符串 4. 字符串查找和子字符串 4.1 查找操作 4.2 提取子字符串 5. 字符串比较 6. …

作者头像 李华
网站建设 2026/4/22 20:53:02

电商系统MySQL启动优化实战:从30秒到3秒的飞跃

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 基于电商高并发场景,生成MySQL 8.0最优启动配置:1.分配16GB内存的专用服务器;2.优化innodb_buffer_pool_size等核心参数;3.预加载常用…

作者头像 李华
网站建设 2026/4/17 22:25:29

万能交换函数模板解析

代码功能解析该代码实现了一个通用的交换函数模板&#xff0c;能够交换任意相同类型的两个变量值。以下是具体分析&#xff1a;模板函数定义template<class T> void Swap(T& x, T& y) {T tmp x;x y;y tmp; }使用template<class T>定义模板&#xff0c;T…

作者头像 李华
网站建设 2026/4/18 10:11:30

Vulkan教程(十三):着色器模块:Vulkan 可编程管线的核心载体

目录 一、SPIR-V 的核心优势 二、Slang 着色器语言基础 三、三角形渲染的着色器实现 3.1 顶点着色器(Vertex Shader) 3.2 片段着色器(Fragment Shader) 3.3 逐顶点颜色插值(进阶) 四、着色器编译(Slang → SPIR-V) 4.1 着色器文件组织 4.2 编译脚本(平台专属…

作者头像 李华
网站建设 2026/4/19 2:15:41

腾讯游戏单季收入破600亿元 :“铁王座”稳中有忧?

近日&#xff0c;腾讯在2025年第三季度财报中披露&#xff0c;总营收达1928.7亿元&#xff0c;同比增长15%&#xff1b;其中游戏业务收入为636亿元&#xff0c;同比增长22.8%&#xff0c;实现单季收入首次突破600亿元大关。这一里程碑标志着腾讯游戏在“回归大DAU、打造长青游戏…

作者头像 李华