blob.slice() 和 file.slice() 行为一致,返回惰性 blob 切片,零拷贝、不触发读取;分片后需手动包装为 file 以保留元信息,合并时会全量加载内存,故仅用于校验。

什么是 Blob.slice() 和 File.slice() 的实际行为
两者本质相同:File 继承自 Blob,slice() 方法在两个类型上行为一致,返回新的 Blob 对象,不触发读取或解码,纯内存引用切割(底层是字节范围映射),零拷贝、低开销。
关键点:slice() 不修改原对象,也不加载内容到 JS 内存;切片结果仍是惰性对象,直到你用 FileReader、URL.createObjectURL() 或 arrayBuffer() 等方法真正读取时才触发数据提取。
常见误判:以为 slice() 会立刻生成新二进制数据——其实不会。这也是它适合大文件分片的根本原因。
如何安全地分片并避免越界和类型丢失
分片逻辑本身简单,但容易在边界和类型处理上出错。尤其当原始对象是 File 时,切片后得到的是 Blob,丢失 name、lastModified 等元信息,上传时可能影响后端识别。
- 始终用
Math.min()控制末尾片大小,防止start + chunkSize > blob.size导致空Blob(Chrome 返回空,Firefox 可能抛错) - 手动补全元信息:对每个切片
Blob,可用new File([blob], originalFile.name, { type: originalFile.type })包一层,恢复为File实例(注意:这不会复制数据,只是包装) - 起始偏移量必须是整数,且推荐用
start = i * chunkSize而非累积加法,避免浮点误差导致错位 -
slice()的第三个参数contentType很少需要传——它只设置新Blob的type,不影响内容解析;若需保持原类型,显式传blob.type
分片后怎么拼回去?前端能否无损还原原始 File?
不能直接“拼回”成同一个 File 对象,但可以合成内容等价的 File 或 Blob。重点不是还原对象身份,而是保证二进制一致性。
用于端到端视频本地化流程的轻量编排器,路由至四个专注子技能——/wjs-transcribing-audio、/wjs-translating-subtitles...
实操路径:
- 用
Promise.all(chunks.map(blob => blob.arrayBuffer()))并行读取所有分片的ArrayBuffer - 合并 ArrayBuffer:用
Uint8Array分配总长度缓冲区,逐个set()写入 - 用
new Blob([mergedUint8Array.buffer], { type: original.type })构造新Blob - 如需
File,再包一层:new File([blob], original.name, { lastModified: original.lastModified })
注意:合并过程会将全部数据载入内存,1GB 文件分 100 片,合并时至少占用 1GB RAM —— 这正是分片的意义所在:避免单次全量加载。所以“拼回去”仅用于校验或调试,生产中应由服务端完成合并。
为什么 FileReader.readAsArrayBuffer() 比 readAsDataURL() 更适合分片上传
readAsDataURL() 会把二进制转 Base64,体积膨胀约 33%,且编码过程阻塞主线程、无法中断;而分片场景下每片都要走一遍,性能和内存代价都不可接受。
readAsArrayBuffer() 直接暴露原始字节,无转换开销,配合 progress 事件还能精确上报每片上传进度。
- 务必监听
onload而非onloadend获取结果:event.target.result是ArrayBuffer,可直接用于fetch的body - 不要在
onload外访问result——它是异步写入的,未完成时为null - 如果用
fetch上传,直接传blob.slice(start, end)即可,无需先读成ArrayBuffer;只有需要校验、加密或加签时才主动读取
真正容易被忽略的是:分片上传的可靠性不取决于前端切多细,而在于断点续传状态管理与服务端分片索引对齐。前端只管按约定生成正确字节范围的 Blob,其余交给协议设计。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










