
文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载Blob 是浏览器中表示“带类型MIME的二进制数据”的高级对象也是 File、上传下载、图片处理与网络请求之间的核心枢纽。本文以《现代 JavaScript 教程》The Modern JavaScript Tutorial即本仓库zh.javascript.info的 Blob 章节为主体完整讲解Blob的构造、切片、URL 化、base64 转换、与ArrayBuffer/Stream的互转并结合仓库 5-network 中的 fetch、FormData、WebSocket、断点续传等章节源码展示 Blob 在真实上传下载场景中的落地用法。读完本文你将能够熟练创建、转换、下载、上传和流式处理任何二进制数据。Blob 是什么带类型的二进制数据在前一章 ArrayBuffer二进制数组 中我们了解到ArrayBuffer及其视图Uint8Array、DataView等是 ECMA 标准的一部分属于 JavaScript 语言本身的二进制能力。而在浏览器中还有更高级的对象——Blob它在 File API 规范中被定义原文链接为 W3C 规范本文不再展开外链。Blob由两部分组成一个可选的字符串type通常是 MIME 类型如image/pngblobParts—— 一系列其他Blob对象、字符串和BufferSource即ArrayBuffer或其上的视图。这一结构可以用本仓库 4-binary/03-blob/blob.svg 直观表示与ArrayBuffer相比Blob的定位更贴近“文件”它自带类型信息天然适合上传/下载、赋值给img/a等场景。构造函数与参数详解Blob构造函数的语法为new Blob(blobParts, options);两个参数的作用如下参数说明blobPartsBlob/BufferSource/String类型值的数组options可选对象•type——Blob类型通常是 MIME 类型例如image/png•endings—— 是否转换换行符使Blob对应于当前操作系统的换行符\r\n或\n。默认为transparent啥也不做也可以是native转换从字符串创建 Blob// 从字符串创建 Blob let blob new Blob([html…/html], {type: text/html}); // 请注意第一个参数必须是一个数组 [...]从类型化数组和字符串创建 Blob// 从类型化数组typed array和字符串创建 Blob let hello new Uint8Array([72, 101, 108, 108, 111]); // 二进制格式的 hello let blob new Blob([hello, , world], {type: text/plain});blobParts可以混合使用字符串与二进制数据这正是 Blob 被设计为“一系列其他 Blob 对象、字符串和 BufferSource”的原因。slice 方法提取 Blob 片段我们可以用slice方法来提取Blob片段blob.slice([byteStart], [byteEnd], [contentType]);三个参数的含义byteStart—— 起始字节默认为 0。byteEnd—— 最后一个字节不包括默认为最后。contentType—— 新 blob 的type默认与源 blob 相同。参数值类似于array.slice也允许是负数。[!NOTE]Blob对象是不可改变的我们无法直接在Blob中更改数据但可以通过slice获得Blob的多个部分从这些部分创建新的Blob对象将它们组成新的Blob等。这种行为类似于 JavaScript 字符串我们无法更改字符串中的字符但可以生成一个新的改动过的字符串。slice在真实项目中的典型应用是断点续传在仓库 5-network/09-resume-upload/article.md 中上传中断后先用额外请求向服务器查询已接收的字节数startByte然后直接用file.slice(startByte)切出剩余部分发送// 文件可以是来自 input.files[0]或者另一个源 xhr.send(file.slice(startByte));这正是 Blob以及继承它的 Fileslice方法在工程中的经典落地。Blob 用作 URL下载与内存管理Blob 可以很容易用作a、img或其他标签的 URL来显示它们的内容。多亏了type我们也可以下载/上传Blob对象而在网络请求中type自然地变成了Content-Type。通过链接下载动态生成的 Blob!-- download 特性attribute强制浏览器下载而不是导航 -- a downloadhello.txt href# idlinkDownload/a script let blob new Blob([Hello, world!], {type: text/plain}); link.href URL.createObjectURL(blob); /script纯 JavaScript 自动下载我们也可以在 JavaScript 中动态创建一个链接通过link.click()模拟点击用户无需任何 HTML 即可下载动态生成的Bloblet link document.createElement(a); link.download hello.txt; let blob new Blob([Hello, world!], {type: text/plain}); link.href URL.createObjectURL(blob); link.click(); URL.revokeObjectURL(link.href);createObjectURL 的内部机制与内存副作用URL.createObjectURL取一个Blob并为其创建一个唯一的 URL形式为blob:origin/uuid也就是link.href的值的样子blob:https://javascript.info/1e67e00e-860d-40a5-89ae-6ab0cbee6273浏览器内部为每个通过URL.createObjectURL生成的 URL 存储了一个URL -Blob映射。因此此类 URL 很短但可以访问Blob。生成的 URL即其链接仅在当前文档打开的状态下才有效它允许引用img、a中的Blob以及基本上任何其他期望 URL 的对象。不过它有个副作用虽然有Blob的映射但Blob本身只保存在内存中浏览器无法释放它。在文档退出时unload该映射会被自动清除因此Blob也相应被释放但如果应用程序寿命很长这个释放就不会很快发生。因此如果我们创建一个 URL那么即使我们不再需要该Blob了它也会被挂在内存中。URL.revokeObjectURL(url)从内部映射中移除引用因此允许Blob被删除如果没有其他引用的话并释放内存。在上面最后一个示例中我们打算仅使用一次Blob来进行即时下载因此立即调用URL.revokeObjectURL(link.href)。而在前一个带有可点击 HTML 链接的示例中我们不调用URL.revokeObjectURL(link.href)因为那样会使BlobURL 无效——调用该方法后由于映射被删除了该 URL 也就不再起作用了。在仓库 5-network/01-fetch/article.md 的“以二进制格式读取响应”示例中也遵循同样的模式img.src URL.createObjectURL(blob)显示图片3 秒后URL.revokeObjectURL(img.src)释放内存let response await fetch(/article/fetch/logo-fetch.svg); let blob await response.blob(); // 下载为 Blob 对象 // 为其创建一个 img let img document.createElement(img); img.style position:fixed;top:10px;left:10px;width:100px; document.body.append(img); // 显示它 img.src URL.createObjectURL(blob); setTimeout(() { // 3 秒后将其隐藏 img.remove(); URL.revokeObjectURL(img.src); }, 3000);Blob 转换为 base64data URL 方案URL.createObjectURL的一个替代方法是将Blob转换为 base64 编码的字符串。这种编码将二进制数据表示为一个由 0 到 64 的 ASCII 码组成的字符串非常安全且“可读”。更重要的是——我们可以直接在data-url中使用此编码其形式为data:[mediatype][;base64],data可以在任何地方使用这种 URL和“常规” URL 一样。例如这是一个内嵌在src中的 base64 图片img srcdata:image/png;base64,R0lGODlhDAAMAKIFAF5LAP/zxAAAANyuAP/gaP///wAAAAAAACH5BAEAAAUALAAAAAAMAAwAAAMlWLPcGjDKFYi9lxKBOaGcF35DhWHamZUW0K4mAbiwWtuf0uxFAgA7浏览器会解码该字符串并显示图像。使用 FileReader 将 Blob 转为 base64我们使用内建的FileReader对象来将Blob转换为 base64。它可以将Blob中的数据读取为多种格式下一章 File 和 FileReader 会更深入地介绍它。下面是下载Blob的示例这次通过 base64let link document.createElement(a); link.download hello.txt; let blob new Blob([Hello, world!], {type: text/plain}); let reader new FileReader(); reader.readAsDataURL(blob); // 将 Blob 转换为 base64 并调用 onload reader.onload function() { link.href reader.result; // data url link.click(); };在 4-binary/04-file/article.md 中可以看到FileReader的readAsDataURL只是三种读取格式之一另外还有readAsArrayBuffer读为ArrayBuffer与readAsText读为字符串是TextDecoder的替代方案。两种 URL 方案对比这两种从Blob创建 URL 的方法都可以用但通常URL.createObjectURL(blob)更简单快捷对比维度URL.createObjectURL(blob)Blob 转换为 data url内存如果介意内存我们需要撤销revoke它们无需撤销revoke任何操作访问方式直接访问Blob无需“编码/解码”对大的Blob进行编码时性能和内存会有损耗Image 转换为 blobcanvas 管线我们可以创建一个图像、图像的一部分甚至一个页面截图的Blob方便将其上传至其他地方。图像操作是通过canvas元素来实现的使用canvas.drawImage在 canvas 上绘制图像或图像的一部分。调用 canvas 方法.toBlob(callback, format, quality)创建一个Blob并在创建完成后使用其运行callback。在下面这个示例中图像只是被复制了不过我们可以在创建 blob 之前从中裁剪图像或者在 canvas 上对其进行转换// 获取任何图像 let img document.querySelector(img); // 生成同尺寸的 canvas let canvas document.createElement(canvas); canvas.width img.clientWidth; canvas.height img.clientHeight; let context canvas.getContext(2d); // 向其中复制图像此方法允许剪裁图像 context.drawImage(img, 0, 0); // 我们 context.rotate()并在 canvas 上做很多其他事情 // toBlob 是异步操作结束后会调用 callback canvas.toBlob(function(blob) { // blob 创建完成下载它 let link document.createElement(a); link.download example.png; link.href URL.createObjectURL(blob); link.click(); // 删除内部 blob 引用这样浏览器可以从内存中将其清除 URL.revokeObjectURL(link.href); }, image/png);如果我们更喜欢async/await而不是 callback可以用一个 Promise 封装let blob await new Promise(resolve canvasElem.toBlob(resolve, image/png));对于页面截图可以使用诸如 html2canvas 之类的库它所做的只是扫一遍浏览器页面并将其绘制在canvas上然后我们就可以像上面一样获取它的Blob。真实案例把 canvas 图片通过 fetch 上传仓库 5-network/01-fetch/article.md 的“发送图片”一节把这条管线用到了网络请求中——用户在canvas上绘制点击按钮后将toBlob得到的 Blob 直接作为fetch的bodyPOST 给服务器async function submit() { let blob await new Promise(resolve canvasElem.toBlob(resolve, image/png)); let response await fetch(/article/fetch/post/image, { method: POST, body: blob }); // 服务器给出确认信息和图片大小作为响应 let result await response.json(); alert(result.message); }请注意这里没有手动设置Content-Typeheader因为Blob对象具有内建的类型这里是image/png通过toBlob生成的。对于Blob对象这个类型就变成了Content-Type的值。同样地在 5-network/02-formdata/article.md 中图片 Blob 可以通过formData.append(image, imageBlob, image.png)作为表单文件字段上传第三个参数fileName设置文件名效果等同于表单中有input typefile nameimage。Blob 转换为 ArrayBufferBlob构造器允许从几乎任何东西创建 blob包括任何BufferSource。但是如果我们需要执行低级别的处理可以从blob.arrayBuffer()中获取最低级别的ArrayBuffer// 从 blob 获取 arrayBuffer const bufferPromise await blob.arrayBuffer(); // 或 blob.arrayBuffer().then(buffer /* 处理 ArrayBuffer */);这与前章 ArrayBuffer二进制数组 的知识形成闭环拿到ArrayBuffer之后可以再在其上创建Uint8Array、DataView等视图进行逐字节的低级别二进制操作。事实上类型化数组Uint8Array等与Blob之间可以双向转换——这正是二进制数据两大体系ECMA 标准与 File API衔接的接口。Blob 转换为 Stream处理超大文件当我们读取和写入超过 2 GB 的 blob 时将其转换为arrayBuffer会占用更多内存。这种情况下我们可以直接将 blob 转换为 stream 进行处理。stream 是一种特殊的对象我们可以从它那里逐部分地读取或写入。对于适合逐段处理的数据使用 stream 很方便。Blob接口里的stream()方法返回一个ReadableStream在被读取时可以返回Blob中包含的数据// 从 blob 获取可读流readableStream const readableStream blob.stream(); const stream readableStream.getReader(); while (true) { // 对于每次迭代value 是下一个 blob 数据片段 let { done, value } await stream.read(); if (done) { // 读取完毕stream 里已经没有数据了 console.log(all blob processed.); break; } // 对刚从 blob 中读取的数据片段做一些处理 console.log(value); }在仓库 5-network/03-fetch-progress/article.md 中可以看到类似的分块思想通过response.body一个ReadableStream逐块读取响应数据把每一块收集进数组最后用new Blob(chunks)把所有块拼成一个 Blob从而在下载过程中实时跟踪进度let blob new Blob(chunks);在真实网络 API 中的 Blob 生态围绕本仓库 5-network 目录可以梳理出 Blob 在浏览器网络层的完整使用图景fetch 响应response.blob()以“带类型的二进制数据”形式返回响应体见 5-network/01-fetch/article.md请求端body可以传string、FormData、BufferSource、Blob或URLSearchParams其中 Blob 的type会自动成为Content-Type。XMLHttpRequestxhr.responseType blob可将响应格式设为Blob适用于二进制数据而.send(body)几乎可以发送任何 body包括Blob和BufferSource见 5-network/08-xmlhttprequest/article.md。WebSocketsocket.send(body)允许 body 是字符串或二进制格式包括Blob、ArrayBuffer等不需要额外设置接收二进制数据时由socket.binaryType决定呈现格式默认为blob——因为 Blob 是高级二进制对象直接与a、img等标签集成若需逐字节处理可改为arraybuffer见 5-network/11-websocket/article.md。断点续传利用Blob.sliceFile 继承自 Blob见 4-binary/04-file/article.md从指定字节处切分文件续传见 5-network/09-resume-upload/article.md。总结ArrayBuffer、Uint8Array及其他BufferSource是“二进制数据”而Blob则表示“具有类型的二进制数据”这方便Blob用于浏览器中非常常见的上传/下载操作。XMLHttpRequest、fetch等 Web 请求方法可以自然地使用Blob也可以使用其他类型的二进制数据。我们可以轻松地在Blob和低级别的二进制数据类型之间进行转换使用new Blob(...)构造函数从一个类型化数组typed array创建Blob使用blob.arrayBuffer()从Blob中取回arrayBuffer然后在其上创建视图view用于低级别的二进制处理处理大型 blob 时将其转换为stream非常有用——Blob接口的stream()方法返回一个ReadableStream其在被读取时返回 blob 中包含的数据。推荐继续阅读本仓库同目录下的姊妹章节以构建完整知识链ArrayBuffer二进制数组 讲底层二进制基础File 和 FileReader 讲 Blob 的子类 File 与读取工具而 5-network 下的 fetch、XMLHttpRequest、WebSocket 与断点续传章节则展示 Blob 在网络传输中的全部实战形态。赞分享文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载相关推荐Modern JavaScript Tutorial 之 Blob浏览器中“带类型的二进制数据”完整实战指南Modern JavaScript Tutorial 之 Blob浏览器中“带类型的二进制数据”完整实战指南 Blob Binary Large Objec文档/教程前端Opium核心概念解析深入理解Handler与Middleware设计模式Opium核心概念解析深入理解Handler与Middleware设计模式 Opium是一个类似Sinatra的OCaml Web工具包其核心设计围绕Han现代 JavaScript 教程浏览器交互函数 alert、prompt 与 confirm 的完整实战指南现代 JavaScript 教程浏览器交互函数 alert、prompt 与 confirm 的完整实战指南 本教程章节 1 js/02 first ste文档/教程前端上一篇CoffeeScript 0.5.4 版本深度解析__filename/__dirname 修复与解析器灵活性提升下一篇TableOptions_RowPinning 接口详解在 TanStack Table 中配置行固定Row Pinning创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考