Web Worker 中 ArrayBuffer 零拷贝处理网络流的核心是移交所有权、视图解析与流式缓冲:主线程用 postMessage(buffer, [buffer]) 转移 ArrayBuffer;Worker 用 Uint8Array/DataView 直接操作字节,避免克隆;流式场景下累积 pending 缓冲并用状态机分帧解析,校验与交付均不复制内存。

在 Web Worker 中用 ArrayBuffer 对接原生二进制网络流,核心是“零拷贝移交 + 状态机解析 + 流式缓冲”。主线程不碰字节,只负责把原始 ArrayBuffer 交给 Worker;Worker 拿到后立刻用 Uint8Array 或 DataView 解析,边收边拆、边验边转,全程不生成中间字符串或新数组。
主线程:只传 buffer,不碰数据
WebSocket、fetch 响应或 FileReader 得到 ArrayBuffer 后,必须用 postMessage(buffer, [buffer]) 转移所有权:
- WebSocket 接收前设
ws.binaryType = "arraybuffer",确保event.data是 ArrayBuffer 而非 Blob - fetch 响应调用
response.arrayBuffer()获取 buffer,不要走response.blob()再转 - FileReader 的
onload回调中直接取e.target.result(已是 ArrayBuffer),立即 transfer - 切记传的是
buffer,不是new Uint8Array(buffer)—— 后者会触发结构化克隆,失去零拷贝优势
Worker 内:用视图操作,不新建内存
Worker 收到消息后,用视图快速访问字节,所有逻辑围绕原始 buffer 展开:
- 入口守卫:
if (!(e.data instanceof ArrayBuffer)) return,防止传错类型 - 创建视图:
const bytes = new Uint8Array(e.data)或const dv = new DataView(e.data) - 解析头部字段(如 magic number、length、crc)用 DataView,支持指定字节序:
dv.getUint16(0, false)(大端) - 批量读写 payload 用 Uint8Array,
bytes.subarray(offset, offset + len)不拷贝内存,只建新视图 - 避免
Uint8Array.from()、slice()、concat()等分配新数组的操作
流式场景:累积缓冲 + 边界识别
网络流往往是分帧到达的,Worker 需维护内部缓冲区,等齐一帧再处理:
- 声明一个
let pending = new Uint8Array(0),每次收到新 buffer 就pending = concatUint8(pending, new Uint8Array(e.data)) - 写一个简单状态机:检查开头是否有 magic 字节 → 读取长度字段 → 判断当前 pending 是否够长 → 够则切出一帧,更新 pending 剩余部分
- 帧内校验(如 CRC32)直接在
pending.subarray(...)上算,不复制整块 - 处理完一帧后,用
postMessage({ type: 'frame', data: frameBytes.buffer }, [frameBytes.buffer])把结果 buffer 转回主线程
结果交付:还原可用,不卡 UI
主线程收到解析后的 ArrayBuffer,可立刻转为业务所需格式:
-
const result = new Uint8Array(e.data)—— 视图重建,零成本 - 若需 JSON,先用
TextDecoder解码:new TextDecoder().decode(result) - 若需 Blob(如下载或上传),
new Blob([result], {type: 'application/octet-stream'}) - 若需 canvas 图像,
createImageBitmap(new Blob([result]))直接解码

















