当前位置:首页 > 文章列表 > 文章 > 前端 > Web Worker 使用 Transferable 后如何把结果传回主线程

Web Worker 使用 Transferable 后如何把结果传回主线程

来源:17golang原创 2026-09-12 23:58:09 0浏览 收藏

Web Worker 使用 Transferable 传输二进制结果时,关键不是“把结果复制回来”,而是把结果的所有权再次交给主线程。最常见的写法是:主线程把 ArrayBuffer 放进消息,同时把同一个 buffer 放入 transfer 列表;Worker 处理后创建新的输出 buffer,再通过第二次 postMessage 转回主线程。转移完成后,原发送端的 buffer 会被 detach,不能继续当作可读写内存。

要点速览
  • Transferable 传的是资源所有权,不是复制;发送端的 ArrayBuffer 转移后 byteLength 为 0。
  • Uint8Array 这类 TypedArray 本身不是 Transferable,应该转移它的 buffer
  • 回传时让 Worker 创建独立输出 buffer,并在消息回调中重新建立主线程视图。

先把消息对象和转移资源对应起来

postMessage 的第一个参数是消息数据,第二个参数是要转移所有权的对象数组。transfer 列表只声明哪些资源要转移,并不会自动把资源塞进消息;因此消息里必须真的引用同一个 ArrayBuffer。下面的代码把字节数组作为消息载荷,转移其底层 buffer:

// main.js:把大块二进制输入交给 Worker,转移的是底层 buffer
const worker = new Worker("worker.js", { type: "module" });
const input = new Uint8Array([10, 20, 30, 40]);

worker.postMessage({
  kind: "sum-bytes",
  bytes: input.buffer, // 消息必须携带这个可转移资源
}, [input.buffer]); // 第二个参数交接 ArrayBuffer 的所有权

// 转移后发送端不再拥有这段内存,视图的 byteLength 会变为 0
console.log(input.byteLength); // 0

worker.addEventListener("message", (event) => {
  // Worker 回传的是新的 ArrayBuffer,主线程重新建立视图
  const output = new Uint8Array(event.data);
  console.log(output[0]);
});

这里转移的是 input.buffer,不是 input。TypedArray 可以被结构化克隆,但它自身不能放进 transfer 列表;它只是一个带偏移量和长度信息的视图,真正拥有字节存储的是底层 buffer。

Web Worker Transferable 输入边界示意图,展示 Uint8Array、ArrayBuffer、postMessage 消息和发送端 detach 关系
图1:Transferable 输入边界操作示意图,展示 Uint8Array 视图、ArrayBuffer 资源和消息对象的对应关系;这是静态结构示意,不是运行截图。

Worker 回传时要交接一个新的结果 buffer

如果 Worker 需要修改原始数据,可以直接在 Worker 一侧使用收到的 buffer,但回传给主线程时更容易维护的做法是创建输出数组。这样输入和输出各自有清晰的所有权,主线程也不会误以为原来的输入视图还能复用。

// worker.js:读取输入并创建独立结果,再把结果转回主线程
self.addEventListener("message", (event) => {
  const input = new Uint8Array(event.data.bytes);
  const output = new Uint8Array(input.length);

  for (let i = 0; i 

第二次转移后,Worker 中的 output 也不再可用;主线程收到消息后,event.data 才是新的 ArrayBuffer 所有者。不要在 postMessage 后继续读取或写入已经转出的视图,也不要把一个已经 detach 的 buffer 再次放进 transfer 列表。

Web Worker Transferable 结果回传示意图,展示 Worker 输出 ArrayBuffer、transfer 列表和主线程结果视图
图2:Worker 结果回传结果示意图,展示新建输出 buffer 从 Worker 交给主线程后的所有权边界;这是静态结构示意,不是执行结果截图。

结构化克隆、Transferable 和共享内存怎么选

三种方式解决的问题不同,不应只因为“数据量大”就盲目改成 Transferable:

方式所有权适合场景注意点
结构化克隆两边各有副本配置、小对象、需要保留发送端数据大块二进制可能产生复制成本
Transferable一次只由一边拥有ArrayBuffer、MessagePort、ImageBitmap 等资源交接发送端会 detach,需明确生命周期
SharedArrayBuffer两边共享同一块内存需要双方协作访问的高性能场景同步、隔离与部署条件更复杂

如果主线程发送后还要继续使用原始字节,就选结构化克隆,或在发送前主动复制一份;如果任务是“交给 Worker 处理,处理完再交回来”,Transferable 的单向所有权模型更清楚。共享内存则要额外设计并发协调,不能把它当作 Transferable 的简单替代。

四个容易踩到的生命周期边界

  1. 消息和 transfer 不匹配:把 buffer 放入列表却不放进消息,接收端拿不到资源,而且发送端仍会失去它。
  2. 转移了视图而不是底层资源:Uint8Array 使用 transfer 会抛出异常,应使用 view.buffer,并留意视图的 offset 与 length。
  3. 回调外继续使用旧变量:主线程收到返回结果前,不能假设原输入仍有效;把后续逻辑放在 message 回调或 Promise 封装内。
  4. 忽略异常与关闭:worker 同时监听 errormessageerror,任务完成且不再复用时调用 terminate()

相关问题

Transferable 会不会复制 ArrayBuffer?

ArrayBuffer 来说,重点是转移底层资源并让原对象 detach,而不是在两个线程各保留一份可写副本。具体资源的转移机制由对应接口定义。

为什么 postMessage 之后原来的 byteLength 变成 0?

这是所有权交接的可见结果。发送端不再拥有这段内存,因此应把它视为不可用状态,等待接收端回传新的 buffer 或重新创建输入。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go log.Fatal 放在库代码里为什么会终止宿主程序Go log.Fatal 放在库代码里为什么会终止宿主程序
上一篇
Go log.Fatal 放在库代码里为什么会终止宿主程序
Go GODEBUG 设置只对一次运行生效吗
下一篇
Go GODEBUG 设置只对一次运行生效吗
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    108次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    23次使用
  • OpenCompass大模型评测体系详解:功能、使用指南与应用场景
    OpenCompass
    OpenCompass是上海AI实验室推出的开源大模型评测平台,提供CompassKit、CompassHub和CompassRank三大核心组件,支持LLM及多模态模型的一站式标准化评估与排行榜查询。
    41次使用
  • AGI-Eval大模型评测平台:权威榜单、数据集与人机协同评测方案
    AGI-Eval
    AGI-Eval是由上海交大等高校联合发布的大模型评测社区,提供公正透明的LLM能力榜单、多领域评测集及Data Studio数据服务,助力AI模型性能评估与NLP科研开发。
    23次使用
  • SuperCLUE中文大模型评测基准:功能、能力维度与应用指南
    SuperCLUE
    SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
    264次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码