背景

XMLHttpRequest 属性 responseType 是一个枚举字符串值,用于指定响应中包含的数据类型。它还允许作者更改响应类型。如果将 responseType 的值设置为空字符串,则会使用 text 作为默认值。

  1. arraybuffer“—response 是一个包含二进制数据的 JavaScript ArrayBuffer
  2. blob“—response 是一个包含二进制数据的 Blob 对象。
  3. document“—response 是一个 HTML DocumentXML XMLDocument,根据接收到的数据的 MIME 类型而定。请参阅 HTML in XMLHttpRequest 中的 HTML,了解有关使用 XHR 获取 HTML 内容的更多信息。
  4. json“—response 是通过将接收到的数据内容解析为 JSON 而创建的 JavaScript 对象。
  5. text“—responseDOMString 对象中的文本。
  6. ms-stream“—response 是流式下载的一部分;此响应类型仅允许用于下载请求,并且仅受 Internet Explorer 支持。

    将 responseType 设置为特定值时,作者应确保服务器实际发送的响应与该格式兼容。如果服务器返回的数据与设置的 responseType 不兼容,则 response 的值将为null .

正文

事实上,前端很少涉及对二进制数据的处理,但即便如此,我们偶尔总能在角落里看见它们的身影。本篇文章重点讲一讲前端的二进制家族:BlobArrayBufferBuffer

概述

  • Blob: 前端的一个专门用于支持文件操作的二进制对象
  • ArrayBuffer:前端的一个通用的二进制缓冲区,类似数组,但在API和特性上却有诸多不同
  • Buffer:Node.js提供的一个二进制缓冲区,常用来处理I/O操作

    Blob

    Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。
    Blob 表示的不一定是JavaScript原生格式的数据。File 接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。
    在前端工程中,我们在哪些操作中可以获得File对象呢?
    image.png
    我们上面说了,File对象是一种特殊的Blob对象,那么它自然就可以直接调用Blob对象的方法。让我们看一看Blob具体有哪些方法,以及能够用它们实现哪些功能
    image.png

    Blob实战

    通过window.URL.createObjectURL方法可以把一个blob转化为一个Blob URL,并且用做文件下载或者图片显示的链接。
    Blob URL所实现的下载或者显示等功能,仅仅可以在单个浏览器内部进行。而不能在服务器上进行存储,或者说它没有在服务器端存储的意义。

    Blob下载

    我们可以通过window.URL.createObjectURL,接收一个Blob(File)对象,将其转化为Blob URL,然后赋给 a.download属性,然后在页面上点击这个链接就可以实现下载了。

    1. <!-- html部分 -->
    2. <a id="h">点此进行下载</a>
    3. <!-- js部分 -->
    4. <script>
    5. var blob = new Blob(["Hello World"]);
    6. var url = window.URL.createObjectURL(blob);
    7. var a = document.getElementById("h");
    8. a.download = "helloworld.txt";
    9. a.href = url;
    10. </script>

    备注:download属性不兼容IE, 对IE可通过window.navigator.msSaveBlob方法或其他进行优化(IE10/11)
    运行结果
    image.png

    Blob图片本地显示

    window.URL.createObjectURL生成的Blob URL还可以赋给img.src,从而实现图片的显示。

    1. <!-- html部分 -->
    2. <input type="file" id='f' />
    3. <img id='img' style="width: 200px;height:200px;" />
    4. <!-- js部分 -->
    5. <script>
    6. document.getElementById('f').addEventListener('change', function (e) {
    7. var file = this.files[0];
    8. const img = document.getElementById('img');
    9. const url = window.URL.createObjectURL(file);
    10. img.src = url;
    11. img.onload = function () {
    12. // 释放一个之前通过调用 URL.createObjectURL创建的 URL 对象
    13. window.URL.revokeObjectURL(url);
    14. }
    15. }, false);
    16. </script>

    运行结果
    image.png

    Blob文件分片上传

  • 通过Blob.slice(start,end)可以分割大Blob为多个小Blob

  • xhr.send是可以直接发送Blob对象的

    1. <!-- html部分 -->
    2. <input type="file" id='f' />
    3. <!-- js部分 -->
    4. <script>
    5. function upload(blob) {
    6. var xhr = new XMLHttpRequest();
    7. xhr.open('POST', '/ajax', true);
    8. xhr.setRequestHeader('Content-Type', 'text/plain')
    9. xhr.send(blob);
    10. }
    11. document.getElementById('f').addEventListener('change', function (e) {
    12. var blob = this.files[0];
    13. const CHUNK_SIZE = 20; .
    14. const SIZE = blob.size;
    15. var start = 0;
    16. var end = CHUNK_SIZE;
    17. while (start < SIZE) {
    18. upload(blob.slice(start, end));
    19. start = end;
    20. end = start + CHUNK_SIZE;
    21. }
    22. }, false);
    23. </script>

    Node端

    1. app.use(async (ctx, next) => {
    2. await next();
    3. if (ctx.path === '/ajax') {
    4. const req = ctx.req;
    5. const body = await parse(req);
    6. ctx.status = 200;
    7. console.log(body);
    8. console.log('---------------');
    9. }
    10. });

    运行结果
    image.png

    本地读取文件内容

    如果想要读取Blob或者文件对象并转化为其他格式的数据,可以借助FileReader对象的API进行操作

  • FileReader.readAsText(Blob):将Blob转化为文本字符串

  • FileReader.readAsArrayBuffer(Blob): 将Blob转为ArrayBuffer格式数据
  • FileReader.readAsDataURL(): 将Blob转化为Base64格式的Data URL

下面我们尝试把一个文件的内容通过字符串的方式读取出来

  1. <input type="file" id='f' />
  2. document.getElementById('f').addEventListener('change', function (e) {
  3. var file = this.files[0];
  4. const reader = new FileReader();
  5. reader.onload = function () {
  6. const content = reader.result;
  7. console.log(content);
  8. }
  9. reader.readAsText(file);
  10. }, false);

运行结果
image.png
上面介绍了Blob的用法,我们不难发现,Blob是针对文件的,或者可以说它就是一个文件对象,同时呢我们发现Blob欠缺对二进制数据的细节操作能力,比如如果要具体修改某一部分的二进制数据,Blob显然就不够用了,而这种细粒度的功能则可以由下面介绍的ArrayBuffer来完成。
让我们用一张图看下ArrayBuffer的大体的功能
image.png
同时要说明,ArrayBuffer跟JS的原生数组有很大的区别,如图所示
image.png

读取本地数据

  1. document.getElementById('f').addEventListener('change', function (e) {
  2. const file = this.files[0];
  3. const fileReader = new FileReader();
  4. fileReader.onload = function () {
  5. const result = fileReader.result;
  6. console.log(result)
  7. }
  8. fileReader.readAsArrayBuffer(file);
  9. }, false);

运行结果
image.png

读取Ajax请求数据

  • 通过xhr.responseType = “arraybuffer” 指定响应的数据类型
  • 在onload回调里打印xhr.response
    1. const xhr = new XMLHttpRequest();
    2. xhr.open("GET", "ajax", true);
    3. xhr.responseType = "arraybuffer";
    4. xhr.onload = function () {
    5. console.log(xhr.response)
    6. }
    7. xhr.send();
    Node部分
    1. const app = new Koa();
    2. app.use(async (ctx) => {
    3. if (pathname = '/ajax') {
    4. ctx.body = 'hello world';
    5. ctx.status = 200;
    6. }
    7. }).listen(3000)
    运行结果
    image.png

    TypeArray对ArrayBuffer进行写操作

    ```javascript const typedArray1 = new Int8Array(8); typedArray1[0] = 32;

const typedArray2 = new Int8Array(typedArray1); typedArray2[1] = 42;

console.log(typedArray1); // output: Int8Array [32, 0, 0, 0, 0, 0, 0, 0]

console.log(typedArray2); // output: Int8Array [32, 42, 0, 0, 0, 0, 0, 0]

  1. <a name="eNRAi"></a>
  2. #### DataView对ArrayBuffer进行写操作
  3. ```javascript
  4. const buffer = new ArrayBuffer(16);
  5. const view = new DataView(buffer);
  6. view.setInt8(2, 42);
  7. console.log(view.getInt8(2));
  8. // 输出: 42

参考文件:https://www.cnblogs.com/penghuwan/p/12053775.html