持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
你一定会遇到过的Blob
相信每个前端开发者在职业生涯中肯定都会遇到过Blob,但却很少有人真的了解过这个东西究竟是什么。今天我们就一起来聊聊Blob吧。
什么是Blob?
首先我们需要知道Blob是JavaScript提供的一离二进制最近的对象。JavaScript作为一门高级语言,甚至大部分的代码都运行在浏览器中,因此JavaScript开发者实际上是很少机会与原生文件或者二进制接触的。但在某些场景下我们又不得不对二进制文件做一些操作,因此JavaScript为我们提供了Blob这个类型。Blob就是专门处理文件操作的。
如何创建一个Blob?
既然我们要讲Blob,我们需要先得到一个Blob。其中最简单的方法就是new一个出来。
new Blob(array, options)
// 参数说明
// - array: 一个由ArrayBuffer, ArrayBufferView, Blob, string objects,或者混合了前面内容的objects组成的数组。
// - options(选填):
// - type: 描述Blob的类型,如 'text/html'
举个例子,我们可以通过下面的代码得到一个HTML文本Blob。
const array = ['<a id="a"><b id="b">hey!</b></a>'];
const blob = new Blob(array, {type : 'text/html'});
Blob属性
通过打印上面代码生成的Blob,我们可以看到Blob有什么属性。
const array = ['<a id="a"><b id="b">hey!</b></a>'];
const blob = new Blob(array, {type : 'text/html'});
console.log(blob);
可以看到Blob有2个属性:
- size: Blob的大小,注意这里的单位是bytes(字节)
- type:Blob的类型
实际中我们更有可能这样得到Blob
前面我们讲了怎么可以主动创建Blob。但在实际工作中又前端开发者主动创建Blob的情况是很少的。我们更多时候是通过API获得Blob。
从文件中获得
既然Blob是描述文件二进制的对象,我们当然能从文件中获得Blob。在浏览器中我们有2种方式获得文件:
- 通过标签获得
- 通过用户拖放操作获得
相信有过这方面业务经验的朋友看到这里应该会发现,通过以上2种方式得到的内容其实跟前文讲的Blob并不完全相同。一般会得到下图的内容:
这里的FileList对象是File对象是集合,而File对象又是一个基于Blob类型。File会针对文件增加一些属性,如文件名称,大小和类型等:
从canvas转换
除了从文件中获得以外,还有一种不常见的方式。就是通过调用canvas元素的toBlob()方法。
HTMLCanvasElement.toBlob(callback, type, quality)
该方法有3个参数:
- callback:转换后的回调
- type(选填):转换类型,默认是image/png
- quality(选填):转换质量,一个0-1的数字。1就是质量最好。
关于Blob的实用操作
说完了怎么可以得到Blob之后,我们再来看看拿到Blob之后,我们可以做什么?
URL.createObjectURL(blob)
我们先来看一个API,URL.createObjectURL(blob)可以把一个Blob转成一个URL。观察下面的例子:
const array = ['<a id="a"><b id="b">hey!</b></a>'];
const blob = new Blob(array, { type: "text/html" });
const url = URL.createObjectURL(blob);
console.log(url);
打印内容为:
很明显可以看到这个URL用的是一个blob开头的协议,严格来说这个并不是一个真的协议,他是一个只能用在浏览器内部的引用地址。因此,不同于base64,这个url不会因为文件越大而越长。有了这个blob url之后我们就可以实现接下来的操作了。
提供下载URL
虽然blob url只能在浏览器内部使用,但通过a标签我们可以作出一个主动下载的动作,让用户把blob像文件一样下载到本地。
<a id="h">点此进行下载</a>
<script>
const array = ['<a id="a"><b id="b">hey!</b></a>'];
const blob = new Blob(array, { type: "text/html" });
const url = URL.createObjectURL(blob);
var a = document.getElementById("h");
a.download = "helloworld.html";
a.href = url;
</script>
加载文件
通过input标签或者拖拉得到的File对象,我们是无法直接使用的。但通过把Blob转成url的形式,可以让img标签加载图片。
<img src="" id="img" />
<input type="file" id="file" />
<script>
const $file = document.querySelector("#file");
const $img = document.querySelector("#img");
$file.addEventListener("change", () => {
const file = $file.files[0];
const url = URL.createObjectURL(file);
$img.src = url;
console.log(url);
});
</script>
文件分片上传
这个是跟服务器相关的功能,在某些时候我们需要从客户端上传文件到服务器。但如果文件太大,在网络不稳定的情况下有可能出现上传出错的问题,
Blob类型有一个slice方法,跟数组的slice一样,可以把Blob切成多个片段。通过把一个文件Blob切成多个片段再逐一上传,这就是分片上传的原理。
具体做法如下:
- 先确定每个片段的大小(每次上传多大的内容)
- 判断出需要把文件切成几份
- 逐一上传
- 每次确保前一个上传成功,否则就重新上传当前片段
- 所以片段上传成功后,通知服务器合并文件。
// 获得上传片段
function getBlobChunk (blob,chunkSize){
const BLOB_SIZE = blob.size;
const chunkList = [];
let start = 0;
let end = chunkSize;
while (start < BlOB_SIZE) {
chunkList.push(blob.slice(start, end));
start = end;
end = start + chunkSize;
}
return chunkList;
}
const $file = document.querySelector("#file");
$file.addEventListener("change", () => {
const file = $file.files[0];
const chunkList = getBlobChunk(file, 1024 * 1024 * 2);
let target=chunkList.pop();
while(chunkList.length){
try{
upload(target);
target=chunkList.pop();
}catch(err){
console.log('上传失败,开始重试');
}
}
});
当然上面只是一个简单的演示例子,在真实场景中可能还会涉及一些额外的前后端交互。如果前端需要先拿一个操作id,让后台知道客户端在上传什么以及把上传的片段放到同一个地方。上传完之后根据id通知后台可以合并文件了。当然这个需要大家根据业务,自行设计。
总结
今天我们了解了JavaScript的Blob对象,讲述了获得Blob的方法和途径,以及我们可以用Blob实现一些如本地下载,渲染文件以及分片上传的操作。希望对大家有所帮助。
如果觉得本文对你有一点帮助的话,可以给我点下赞噢~