16
原文地址:https://codeburst.io/javascri...

作者:Dornhoth

如果你已经能让一个用户从你的网站上下载某些文件,那或许你已经遇到过 Blob 类型了。你可能已经在网上检查了一些例子并修改它们,但没有多想这个 Blob 是什么。只要它能工作...

这种知识可以显示初级开发人员和高级开发人员之间的区别。又或者,作为一名初级开发人员,你会因为好奇和渴望学习而脱颖而出。即使你不是在为面试做准备,对 Blob 是什么有一个清晰而简单的理解,也可以帮助你理解下一次在压缩 PDF 文件时,中间遇到的复杂代码,所以我们开始吧:

用法

要下载一些简单的文本,你可以这样做:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Blobs</title>
  <script src="index.js"></script>
</head>

<body>
  <button id="button">Link</button>
</body>

</html>
const download = (fileName, file) => {
  const element = document.createElement('a');
  element.href = file;
  element.download = fileName;
  element.target = '_blank'; 
  element.click();
  element.remove();
}

document.addEventListener('click', async event => {
  if (event.target.id === 'button') {
    const fileName = 'test.txt';
    download(fileName, 'data:text/json;charset=utf-8,File to download');
  }
});

另一方面,对于更复杂的文件,这还不够。如果我们想下载生成 PDF 文件,则必须这样做(这个示例使用 jsPDF):

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Blobs</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.debug.js"></script>
  <script src="index.js"></script>
</head>

<body>
  <button id="button">Link</button>
</body>

</html>
const download = (fileName, blob) => {
  const element = document.createElement('a');
  const url = window.URL.createObjectURL(blob);
  element.href = url;
  element.download = fileName;
  element.target = '_blank'; 
  element.click();
  element.remove();
}

document.addEventListener('click', async event => {
  if (event.target.id === 'button') {
    const doc = new jsPDF();
    const fileName = 'test.pdf';
    doc.text('Hello world!');
    const blob = new Blob([doc.output()]);
    download(fileName, blob);
  }
});

什么是Blob?

Blob 不是 JavaScript 特有的。最初,创建 Blob 是为了在数据库管理系统中使用。该类型创建于1970年代,用于存储音频、图像或视频等大文件,这些文件太大,无法存储在常规数据库字段中。因此这个术语实际上是指“二进制大对象”。

在 JavaScript 中,Blob 用于将文件表示为不可变的原始数据。在控制台中,我们在前面的例子中创建的 Blob,如下所示:

image

如你所见,Blob 有两个属性:大小(size)和类型(type)。大小是以字节为单位的数据大小。类型是一个包 MIME 类型的字符串。创建 Blob 时我没有给出任何类型,但我应该这样做:

const blob = new Blob([doc.output()], { type: 'application/pdf' });

现在我的 Blob 也有一个类型:

image

Blob中有什么?

JavaScript Blob 提供了一些方法来访问它们的内容。其中一个是 text 方法,它以文本(text)形式返回对 Blob 内容的 Promise 解析(技术上是 USVString)。

document.addEventListener('click', async event => {
  if (event.target.id === 'button') {
    const doc = new jsPDF();
    doc.text('Hello world!');
    const blob = new Blob([doc.output()], { type: 'application/pdf' });
    const blobAsText = await blob.text();
    console.log(blobAsText);
  }
});

这给了我们一个相当不好理解的内容:

%PDF-1.3
3 0 obj
<</Type /Page
/Parent 1 0 R
/Resources 2 0 R
/MediaBox [0 0 595.28 841.89]
/Contents 4 0 R
>>
endobj
4 0 obj
<</Length 67>>
stream
0.57 w
0 G
BT
/F1 16 Tf
18.4 TL
0 g
NaN NaN Td
(Hello world!) Tj
ET
endstream
endobj
1 0 obj
<</Type /Pages
/Kids [3 0 R ]
/Count 1
>>
endobj
5 0 obj
<</BaseFont/Helvetica/Type/Font
/Encoding/WinAnsiEncoding
/Subtype/Type1>>
endobj
6 0 obj
...

能做的事情并不多,但它给了你一个机会,让你了解文件内部长什么样子。

还有另外两种方法可以让你访问 Blob 的内容:

  • arrayBuffer,将返回一个 Promise 解析到 ArrayBuffer
  • stream,将返回一个可读流(ReadableStream)

操作 Blob

你定期从 HTTP 请求接收文件。如果使用 fetch API,则需要使用 body 上的 blob 方法从响应中读取 blob:

document.addEventListener('click', async event => {
  if (event.target.id === 'button') {
    fetch('https://whatever/doc.pdf')
    .then(response => response.blob())
    .then(blob => {
      download('test.pdf', blob);
    });
  }
});

在前面的示例中,我们使用库创建了一个 PDF 文件,并从中创建了一个 Blob。

你还可以从另一个 Blob 创建一个 Blob。您只能对原始 Blob 进行切片(slice),也就是说只返回其字节的一部分。

document.addEventListener('click', async event => {
  if (event.target.id === 'button') {
    const blob = new Blob(['some text'], { type: 'application/pdf' });
    const slicedBlob = blob.slice(5, 9);
    const blobAsText = await blob.text();
    const slicedBlobAsText = await slicedBlob.text();

    console.log(`Original Blob: ${blobAsText}`);
    console.log(`Sliced Blob: ${slicedBlobAsText}`);
  }
});

image

这对于非常简单的 Blob 可能很有用,但是对于更复杂的文件,这可能会损坏您的文件并使切片的 Blob 不可读。

我希望你现在能理解 Blob 的用法。这是一种非常简单的数据类型,用于将文件表示为原始数据。如果您想了解更多细节,可以查看文档:

https://developer.mozilla.org/en-US/docs/Web/API/Blob


诺顿
1.5k 声望327 粉丝

不忘初心,方得始终。