什么是Blob对象
Blob对象在MDN官方文档中是这样解释的:
Blob对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成ReadableStream来用于数据操作。
其实一开始看到这个解释的时候还是有点懵逼,不可变、原始数据的类文件对象。那么什么是类文件对象呢?
我们知道,我们平时开发用的对象是javascript对象,有很多属性和方法,供我们去调用和访问。那类文件对象,顾名思义,也就是类似于文件的对象。说简单点,也就是描述一个文件的对象,可以访问他的大小(Blob.size)、类型(Blob.type)等信息,还可以对该对象进行一些操作,比如说文件切片;
不难看出,它就是用来描述我们一个文件类型的实例对象;
创建Blob对象时发生了什么
相信很多小伙伴都会遇到一个面试题,当创建一个javascript对象时都发生了什么?是的,我们这里来研究一下当创建一个Blob对象时都发生了什么?
我们先写代码,首先我们在HTML文件中声明一个<input id="file" type="file">标签,在js中通过new Blob()实例化一个Blob对象:
new Blob([new Int32Array()], {type: 'text/html'})
这里我们创建了一个32位有符号的整型数组,类型时'text/html'。
好下一步我们在浏览器的导航栏输入chrome://blob-internals/,查看一下浏览器内部Blob的存储情况:
我们就会看到这样一个blob示例,它是对我们当前创建的Blob对象的一个描述。
我们先来看一下Blob对象源码是如何实现的:
[Exposed=(Window,Worker), Serializable]
interface Blob {
constructor(optional sequence<BlobPart> blobParts,
optional BlobPropertyBag options = {});
readonly attribute unsigned long long size;
readonly attribute DOMString type;
Blob slice(optional [Clamp] long long start,
optional [Clamp] long long end,
optional DOMString contentType);
[NewObject] ReadableStream stream();
[NewObject] Promise<USVString> text();
[NewObject] Promise<ArrayBuffer> arrayBuffer();
};
enum EndingType { "transparent", "native" };
dictionary BlobPropertyBag {
DOMString type = "";
EndingType endings = "transparent";
};
typedef (BufferSource or Blob or USVString) BlobPart;
Blob()可以使用零个或多个参数调用构造函数 。Blob()调用构造函数时,调用时会经过以下步骤:
-
如果无调用,则返回一个
Blob由 0 字节组成的新对象,size设置为 0,type设置为空字符串。 -
让
bytes是处理给定的blob 部分blobParts的结果和options。 -
如果参数的
type成员options不是空字符串,请运行以下子步骤:- 使
t成为type字典成员。如果t包含 U+0020 到 U+007E 范围之外的任何字符,则将t设置为空字符串并从这些子步骤返回。 - 将
t中的每个字符转换为小写ASCII。
- 使
-
返回一个
Blob引用bytes的对象作为其关联的字节序列,并将其size设置为bytes的长度,并将其type设置为上述子步骤中的t值。
什么场景使用
同学们在开发的时候,通常会在请求application/octet-stream字节流类型数据时使用,或者当前端本地需要上传二进制文件时使用。
而且我们常用的File对象也是继承自Blob对象的,比较常见的场景就是在操作或者存储我们二进制文件时,转化为可序列化的javascript对象时使用;
基本属性和方法
接下来会简单介绍一下几个常用的API。
const blob = new Blob(["掘金"], { type: 'text/html' });
console.log(blob.size) // 6
console.log(blob.type) // text/html
Blob.size
这是个只读属性,表示查看我们Blob对象中内容的大小,是以自己为单位的:
我们知道,在UTF8中我们一个汉字占三个字节,所以这里我们一个一共两个汉字,就是6个字节;
Blob.type
这也是个只读属性,表示当前我们存储的数据类型;其实也就是Blob构造函数的第二个对象参数中的type字段的value;
Blob.slice
这个是原型上的方法, 官方的说法是创建包含指定字节范围的新Blob对象。说白了就是把一个Blob对象切片成多个小的文件;
一共有三个参数(均为非必传):
-
start:是一个
number类型,表示会被拷贝到新的Blob对象中的其实字节,如果是负数,将会自后像前数,例如-100,就是倒数第100个字节,如果传入的长度大于目标Blob对象的字节长度,将会返回长度为0的空Blob对象; -
end:这个参数代表的是
Blob的一个下标,这个下标-1的对应的字节将会是被拷贝进新的Blob的最后一个字节。如果你传入了一个负数,那么这个偏移量将会从数据的末尾从后到前开始计算。举例来说, -10 将会是Blob的倒数第十个字节。它的默认值就是它的原始长度(size). -
给新的
Blob赋予一个新的文档类型。这将会把它的 type 属性设为被传入的值。它的默认值是一个空的字符串。
首先我先选择上传这样一张图片:
const File = document.getElementById("file");
const uploadHandle = e => {
const fileName = e.target.files[0].name
const type = e.target.files[0].type;
const blob = new Blob([e.target.files[0]], {
type
});
console.log(blob)
console.log(blob.size) // 119498
console.log(blob.type) // image/png
};
File.addEventListener('change', uploadHandle);
通过上面的代码会得到这样的结果:
同时在浏览器的Blob存储器里,也会得到这样一个对象:
具体使用,我们接着上面的代码写:
const File = document.getElementById("file");
const uploadHandle = e => {
const fileName = e.target.files[0].name
const type = e.target.files[0].type;
const blob = new Blob([e.target.files[0]], {
type
});
console.log(blob)
console.log(blob.size) // 119498
console.log(blob.type) // image/png
const fileChunks = [];
const size = 1024 * 3; // 切片大小
const totalsize = blob.size; // 文件尺寸
let start = 0; // 切片位置
while (start <= totalsize) {
const chunk = blob.slice(start, start + size, blob.type);
fileChunks.push({
hash: start,
chunk
});
start += size;
}
console.log(fileChunks)
};
File.addEventListener('change', uploadHandle);
通过上面的方法,我们将每一片分为 1024 * 3 个字节,通过执行循环语句,每次将切片位置向后移动,最后在控制台会得到这样的结果;
这样的话,我们就会对大文件进行切片,形成一个队列,最常用的方式就是消费这个队列去并发上传文件;
Blob.stream()
Blob接口的stream() 方法返回一个ReadableStream对象,读取它将返回包含在Blob中的数据。
Blob.text()
该方法返回的是一个Promise对象,使用的是UTF-8格式编码,主要是读取一些字符串类型;
const HTML = `<div>
<div>
<p>123</p>
</div>
</div>`;
const blob = new Blob([HTML], {
type: 'text/html'
});
blob.text().then(res => console.log(res))
/* 会打印出
<div>
<div>
<p>123</p>
</div>
</div>
*/
Blob.arrayBuffer()
该方法同样返回一个Promise对象, Pormise决议结果返回的是代表内存之中的一段二进制数据,该对象会继承TypedArray对象可以,通过“视图”进行操作;
总结
本篇文章我们主要介绍了一下什么是Blob对象,其实就是一个描述文件的类文件对象。其次我们介绍了一下创建Blob对象时构造函数内都发生了什么。其次简单说了一下常用的应用场景,最后结合代码,介绍了Blob的一些API,希望通过本篇文章,你会对Blob有一个更深刻的认识。