# 二进制数据-Blob

# Blob

Blob(Binary Large Object)表示二进制类型的大对象。Blob 通常是影像、声音或多媒体文件。

Blob 对象 由一个可选的字符串 type(通常是 MIME 类型)和 blobParts 组成

构造函数的语法为:

let blob = new Blob(blobParts, options);

参数:

  • blobParts 是 Blob/BufferSource/String 类型的值的数组
  • options 可选对象 { type: "image/png", endings:"transparent" }

// 从类型化数组(typed array)和字符串创建 Blob
let hello = new Uint8Array([72, 101, 108, 108, 111]); // 二进制格式的 "hello"
let blob = new Blob([hello, " ", "world"], { type: "text/plain" });

我们可以用 slice 方法来提取 Blob 片段

blob.slice([byteStart], [byteEnd], [contentType]);

Blob 对象是不可改变的

我们无法直接在 Blob 中更改数据,但我们可以通过 slice 获得 Blob 的多个部分,从这些部分创建新的 Blob 对象,将它们组成新的 Blob,等。

# Blob 用作 URL

Blob 可以简单认为就是浏览器内置的一个文件系统

Blob 可以很容易用作 <a><img> 或其他标签的 URL,来显示它们的内容。

多亏了 type,让我们也可以下载/上传 Blob 对象,而在网络请求中,type 自然地变成了 Content-Type字段

下面这段代码可以让用户无需任何 HTML 即可下载动态生成的 Blob

let link = document.createElement("a");
link.download = "hello.txt";

let blob = new Blob(["Hello, world!"], { type: "text/plain" });

link.href = URL.createObjectURL(blob); // data url
link.click();

URL.revokeObjectURL(link.href); // 注意下载完之后回收这个URL指向的内存

# Blob 转换为 base64

URL.createObjectURL 的一个替代方法是,将 Blob 转换为 base64-编码的字符串。

我们使用内建的 FileReader 对象来将 Blob 转换为 base64。它可以将 Blob 中的数据读取为多种格式。

下面是下载 Blob 的示例,这次是通过 base-64:

let 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();
};

这个方法的缺点是,当对大的 Blob 进行编码时,性能和内存会有损耗。

# Image 转换为 blob

我们可以创建一个图像(image)的、图像的一部分、或者甚至创建一个页面截图的 Blob。这样方便将其上传至其他地方。

图像操作是通过 <canvas> 元素来实现的:

使用 canvas.drawImage 在 canvas 上绘制图像(或图像的一部分)。 调用 canvas 方法 .toBlob(callback, format, quality) 创建一个 Blob,并在创建完成后使用其运行 callback。

// 获取任何图像
let img = document.querySelector("img");

// 生成同尺寸的 <canvas>
let canvasElem = document.createElement("canvas");
canvas.width = img.clientWidth;
canvas.height = img.clientHeight;

let context = canvas.getContext("2d");

// 向其中复制图像(此方法允许剪裁图像)
context.drawImage(img, 0, 0);
// 我们 context.rotate(),并在 canvas 上做很多其他事情
img2blob();

async function img2blob() {
  let blob = await new Promise((resolve) => canvasElem.toBlob(resolve, "image/png"));

  let link = document.createElement("a");

  link.download = "example.png";
  link.href = URL.createObjectURL(blob);

  link.click();
  // 删除内部 blob 引用,这样浏览器可以从内存中将其清除
  URL.revokeObjectURL(link.href);
}

# Blob 转换为 ArrayBuffer

Blob 构造器允许从几乎所有东西创建 blob,包括任何 BufferSource。

但是,如果我们需要执行低级别的操作的话,则可以使用 FileReader 从 blob 中获取最低级别的 ArrayBuffer

// 从 blob 获取 arrayBuffer
let fileReader = new FileReader();

fileReader.readAsArrayBuffer(blob);

fileReader.onload = function (event) {
  let arrayBuffer = fileReader.result;
};

# 总结

ArrayBuffer,Uint8Array 及其他 BufferSource 是“二进制数据”,而 Blob 则表示“具有类型的二进制数据”。

这样可以方便 Blob 用于在浏览器中非常常见的上传/下载操作。

XMLHttpRequest,fetch 等进行 Web 请求的方法可以自然地使用 Blob,也可以使用其他类型的二进制数据。