WebGPU 入门如何把计算结果回传页面:GPUBuffer、mapAsync 与设备丢失处理
页面里的 WebGPU 计算已经提交,JavaScript 却拿不到结果,问题通常不在 WGSL 公式,而在“GPU 可写的缓冲区”和“JavaScript 可读的缓冲区”没有分开。可靠的回传路径是:计算写入 output,命令编码器把它复制到 stagingBuffer,再等待 mapAsync 完成,读取 getMappedRange,最后 unmap。
把 GPU 结果交给页面,关键不是直接读取 output,而是用
GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST创建 stagingBuffer,并严格遵守映射、读取、解除映射的顺序。
要点速览
output负责接收计算结果,stagingBuffer负责被 JavaScript 读取。copyBufferToBuffer完成 GPU 内部搬运,mapAsync完成异步可读准备。- 设备丢失后,旧设备创建的 buffer、pipeline 等资源都要跟着重建。
先分清 output 和 stagingBuffer 的职责
WebGPU 的 buffer 使用权限是在 device.createBuffer 时声明的。计算输出通常需要 STORAGE | COPY_SRC,因为计算着色器要写入它,之后还要作为复制源;给 JavaScript 读取的 stagingBuffer 则使用 MAP_READ | COPY_DST。MAP_READ 不能和任意用途混搭,先把职责分开,后面的命令才不会在验证阶段失败。
const output = device.createBuffer({
size: BUFFER_SIZE,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
});
const stagingBuffer = device.createBuffer({
size: BUFFER_SIZE,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
});
这里的 output 不是 JavaScript 变量的普通数组,它是 GPU 设备管理的存储;stagingBuffer 也不是“自动同步的镜像”。两者之间必须明确编码一次复制命令。

copyBufferToBuffer 之后再请求 mapAsync
计算 pass 结束后,用 GPUCommandEncoder.copyBufferToBuffer 把 output 的结果复制到 stagingBuffer,再通过 device.queue.submit 提交命令。提交后才能对 stagingBuffer 调用 mapAsync;映射完成前,getMappedRange 不能使用。
const commandEncoder = device.createCommandEncoder();
commandEncoder.copyBufferToBuffer(
output,
0,
stagingBuffer,
0,
BUFFER_SIZE,
);
device.queue.submit([commandEncoder.finish()]);
await stagingBuffer.mapAsync(
GPUMapMode.READ,
0,
BUFFER_SIZE,
);
const mapped = stagingBuffer.getMappedRange(0, BUFFER_SIZE);
const data = mapped.slice(0);
stagingBuffer.unmap();
console.log(new Float32Array(data));
mapAsync 返回的 Promise 兑现,只说明这个范围已经可以被访问;读取完成后要先复制出自己的 ArrayBuffer,再调用 unmap。缓冲区保持 mapped 状态时,不能继续作为 GPU 命令的目标。

改动的重点是映射边界,不是把等待写得更长
如果映射范围从偏移量开始,offset 必须满足 API 的对齐要求,size 也必须落在 buffer 范围内。最稳妥的入门代码是从 0 映射完整的 BUFFER_SIZE,并让它保持 4 字节对齐;等数据结构稳定后,再为多个结果分段设计偏移量。
不要用一个同时承担 STORAGE、MAP_READ 等互相冲突职责的 buffer 代替两个 buffer,也不要在 mapAsync 尚未兑现时读取 mapped range。遇到 OperationError,优先检查 usage、offset、size 和当前 mapState,不要盲目增加延迟。
设备丢失后要重建整套 GPU 资源
GPUDevice.lost 是一个在设备生命周期内保持 pending、设备丢失时才兑现的 Promise。浏览器资源管理或驱动更新都可能触发设备丢失;如果原因不是主动调用 GPUDevice.destroy,应用可以重新申请 device,但旧 device 创建的 buffer、pipeline 和 bind group 不能继续复用。
device.lost.then((info) => {
console.error(`WebGPU device was lost: ${info.message}`);
if (info.reason !== "destroyed") {
init();
}
});
恢复函数应重新执行适配器申请、设备创建、buffer 创建和 pipeline 初始化。页面层只保留“正在恢复”的状态,避免用户连续点击时把旧设备上的命令再次提交。
常见问题
为什么不能直接对 output 调用 mapAsync?
output 通常使用 STORAGE | COPY_SRC,并没有 MAP_READ 权限。把结果复制到使用 MAP_READ | COPY_DST 创建的 stagingBuffer,才是常见的 GPU 到 JavaScript 回传路径。
mapAsync 完成后还要调用 unmap 吗?
要。读取 mapped range 并复制出数据后调用 unmap,缓冲区才重新对 GPU 命令可用;不要把 mapped 状态当成永久读取模式。
设备丢失后只重新 requestDevice 可以吗?
不够。旧设备拥有的 buffer、pipeline、bind group 等资源都需要重建,恢复流程应回到初始化阶段,并暂时阻止旧任务继续提交。
最小验收:看得到结果,也能处理失效设备
一个可交付的 WebGPU 回传实现,至少应能在控制台看到从 output 复制来的数值,确认 mapAsync 只在提交复制命令后调用,并在读取后执行 unmap。再人为触发设备失效或模拟恢复路径,确认 GPUDevice.lost 会重新创建整套资源。这样排查时,问题会落在清晰的 buffer 权限、命令顺序或设备生命周期上,而不是一段无法定位的“GPU 没返回结果”。
Linux inotifywait 如何只捕获目录新增文件:事件过滤、递归范围与重复通知
- 上一篇
- Linux inotifywait 如何只捕获目录新增文件:事件过滤、递归范围与重复通知
- 下一篇
- IntersectionObserver 如何避免列表滚动监听抖动:rootMargin、阈值与卸载
-
- 文章 · 前端 | 42分钟前 | 前端 · css · 响应式布局 · Grid布局 · Grid布局 grid-template-rows CSS subgrid 嵌套卡片
- CSS subgrid 如何让嵌套卡片对齐:grid-template-rows、subgrid 与回退布局
- 474浏览 收藏
-
- 文章 · 前端 | 45分钟前 | html · javascript · Web无障碍 · html 模态框 无障碍 inert
- HTML inert 如何锁住模态框背后的页面:焦点隔离、点击拦截与无障碍验收
- 398浏览 收藏
-
- 文章 · 前端 | 1小时前 | javascript · 浏览器API · 滚动列表 · IntersectionObserver 前端性能 rootMargin threshold
- IntersectionObserver 如何避免列表滚动监听抖动:rootMargin、阈值与卸载
- 196浏览 收藏
-
- 文章 · 前端 | 3小时前 | 前端 · javascript · Fetch API · 异步请求 · 竞态条件 Fetch AbortController 前端搜索 请求取消
- 前端 AbortController 如何取消搜索请求:竞态收口、状态复原与可验证示例
- 207浏览 收藏
-
- 文章 · 前端 | 3小时前 | 前端 · 路由 · javascript · 兼容性 · 浏览器 API · 嵌套路由 JavaScript URLPattern URLPattern groups URLPattern test 浏览器 API
- JavaScript URLPattern 如何匹配嵌套路由:groups、test 与降级边界
- 445浏览 收藏
-
- 文章 · 前端 | 4小时前 | javascript · 浏览器API · 前端状态 · file 表单状态 structuredClone DataCloneError
- 前端 structuredClone 复制表单状态:对象克隆、File 数据与不可复制字段怎么排查
- 213浏览 收藏
-
- 文章 · 前端 | 5小时前 |
- 网页长列表怎么用 IntersectionObserver 只触发一次加载:观察状态、哨兵节点与并发收口
- 106浏览 收藏
-
- 文章 · 前端 | 13小时前 | html · 前端 · javascript · 弹窗 · 浏览器API · dialog close cancel HTMLDialogElement requestClose
- HTMLDialogElement requestClose 如何统一弹窗关闭路径:cancel 事件与关闭原因
- 163浏览 收藏
-
- 文章 · 前端 | 15小时前 | 前端 · javascript · 国际化 · JavaScript 中文分词 Intl.Segmenter 搜索高亮
- JavaScript Intl.Segmenter 如何处理中文断词:光标定位与搜索高亮边界
- 111浏览 收藏
-
- 文章 · 前端 | 15小时前 | 前端 · javascript · 国际化 · 文本处理 · JavaScript 多语言 Intl.Segmenter 中文摘要
- Intl.Segmenter 如何按中文词边界截断摘要:word 粒度与多语言回退
- 290浏览 收藏
-
- 文章 · 前端 | 16小时前 | 前端 · 性能 · 浏览器 · css · 长列表 · 前端性能 content-visibility contain-intrinsic-size 大列表 滚动抖动
- 前端大列表为什么滚动会抖:content-visibility 与占位高度的取舍
- 366浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ljg-skills
- ljg-skills 是李继刚开源的 AI 技能与提示词集合,面向大模型使用者整理了一批可复用的 prompt、角色设定和任务技能模板,适合用于学习提示词设计、搭建个人 AI 工作流和沉淀团队常用智能体能力。
- 5438次使用
-
- MELO音乐
- MELO音乐是一站式AI视频与音乐制作助手,对标suno, udio的高品质体验。提供伴奏生成、原创写词、无损导出、哼唱识曲、混音变声等全套音频与短视频编辑工具。无论是流行Kpop、电音说唱、民谣古风、摇滚儿歌还是商用轻音乐,MELO为你免费谱曲,轻松做同款!
- 4921次使用
-
- UniScribe
- UniScribe 是一款 AI 音视频转文字与内容整理工具,支持上传音频、视频文件或粘贴 YouTube 链接,自动生成转写文本、摘要、思维导图和关键问题,并支持多格式导出,适合会议记录、课程学习、访谈整理和内容创作复盘。
- 4842次使用
-
- 剧云
- 剧云是专业中文剧本创作平台,安全稳定运行十余年,集成AI编剧、剧本医生审核、人物小传、剧情关系图、大纲编写、多人协作、Word导入导出、版权管控功能,数据安全防护,轻松高效创作剧本。
- 5106次使用
-
- 万象有声
- 万象有声,一个专为有声创作者打造的新一代智能有声内容创作平台。平台提供专业的智能拆章、智能画本编辑、AI配音、AI生成音效、后期制作、智能对轨、智能审听等有声创作全流程工具,可以帮助创作者高效、低成本创作出引人入胜的有声作品。立即体验,让有声书制作更简单!
- 5061次使用
-
- Go语言对前端领域的入侵WebAssembly运行原理
- 2022-12-31 130浏览
-
- golang 对象深拷贝的常见方式及性能
- 2022-12-28 262浏览
-
- Go标准库http与fasthttp服务端性能对比场景分析
- 2022-12-31 206浏览
-
- golang利用pprof与go-torch如何做性能分析
- 2023-01-01 182浏览
-
- Go语言中三种不同md5计算方式的性能比较
- 2022-12-27 202浏览

