最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript也有操作二进制的一天:聊ArrayBuffer和Blob

    正文概述 掘金(VaporSpace)   2020-12-12   721

    JavaScript也有操作二进制的一天:聊ArrayBuffer和Blob

    就像上图一样,这篇主要介绍Blob和ArrayBuffer相关的一些API之间的关系和用途,并不会详细介绍每个属性和方法,更多的是想讲述清楚一些概念。

    Blob

    我们在做预览本地图片需求时往往需要再<Input>中拿到File对象,再根据File生成一个Blob URL从而放进img src中显示。

    其实<input>中的File实例对象和DataTransfer对象(拖拽)是一个特殊的 Blob 实例,继承了Blob的属性和方法,只是增加了name和lastModifiedDate等专有属性。

    Blob对象表示一个不可变、原始数据的类文件对象,它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream(读写流) 来用于数据操作。

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

        // 从字符串创建 Blob
        const blob = new Blob(['hello', ' ', 'world'], {type: 'text/plain'});
        
        // 截取blob中不同下标之间的字节
        const newBlob1 = blob.slice(0, 2)
        const newBlob2 = blob.slice(6, 8)
        
        // 组合成新的blob
        const newBlob3 = new Blob([newBlob1, ' ', newBlob2], {type: 'text/plain'})
        newBlob3.text().then(console.log) // he wo
    

    Blob URL

    通过URL.createObjectURL可以为Blob生成Blob URL,最常用到的场景就是展示本地图片,将File生成的Blob URL放进img src中。

    和较长的Base64格式的Data URL相比,Blob URL的长度显然不能够存储足够的信息,这也就意味着它只是类似于一个浏览器内部的“引用”。从这个角度看,Blob URL是一个浏览器自行制定的一个伪协议。也正是因为Blob数据是存储在内存中,它的生命周期和创建它的窗口中的document 绑定,所以当用完了这个URL最好手动将其占用的内存释放。如果想要将信息留存下来作为url,将Blob对象转换为base64也是个方案。

    FileReader

    通过FileReader将Blob对象转为字符串、ArrayBuffer和base64

        // 将字符串转换成 Blob对象
        const blob = new Blob(['中文字符串'], {type: 'text/plain'});
        const reader = new FileReader();
        
        // 将Blob 对象转换成字符串
        reader.readAsText(blob, 'utf-8');
        reader.onload = function (e) {
            console.info(reader.result);
        }
        
        // 将Blob 对象转换成 ArrayBuffer
        reader.readAsArrayBuffer(blob);
        reader.onload = function (e) {
            console.info(reader.result); 
        }
        
        // 将Blob 对象转换成 base64
        // FileReader.readAsDataURL()
    

    Blob应用场景:

    • 将blob转为blob URL或data URL作媒体资源,即本地媒体文件显示;
    • 将blob通过slice进行分割从而实现分段上传;
    • canvas输出二进制图像数据;(HTMLCanvasElement.toBlob
    • ...

    ArrayBuffer、TypedArray和DataView

    历史:为了充分利用3D图形API和GPU加速在canvas上渲染复杂图形,出现了WebGL(Web Graphics Library)。但因为JavaScript运行时中的数组并不存在类型,所以当WebGL底层与JavaScript之间传递数据时,需要为目标环境分配新数组,并以当前格式迭代,这将花费很多时间。

    为了解决这个问题,则出现了定型数组(TypeArray)。通过定型数组JavaScript可以分配、读取、写入数组,并直接传给底层图形驱动程序,也可直接从底层获取。

    既然定型数组赋予JavaScript跟底层进行数据交换的能力,那么就同样会出现与其他设备/网络进行二进制数据的交流,应对更复杂的场景,DataView也应运而生。

    他们以数组的语法处理二进制数据,所以统称为二进制数组,TypedArray和DataView可以像C语言一样通过修改下标的方式直接操作内存。

    ArrayBuffer对象存储原始的二进制数据,只是容器,需要TypedArray和DataView来读写。TypedArray视图用来读写单一类型的二进制数据,DataView视图用来读写复杂类型的二进制数据

    ArrayBuffer对象作为内存区域,可以存放多种类型的数据。同一段内存,不同数据有不同的解读方式,这就叫做“视图”(view);

        const buffer = new ArrayBuffer(12);
    
        const x1 = new Int32Array(buffer);
        x1[0] = 1;
        const x2 = new Uint8Array(buffer);
        x2[0]  = 2;
        
        x1[0] // 2
        
        // 由于两个视图对应的是同一段内存,一个视图修改底层内存,会影响到另一个视图。
    

    本来,在设计目的上,ArrayBuffer对象的各种TypedArray视图,是用来向网卡、声卡之类的本机设备传送数据,所以使用本机的字节序就可以了;但由于不同设备的操作系统中字节序的不同,所以需要DataView视图来做支持,它是用来处理网络设备传来的数据,可以自行设定大端字节序或小端字节序;

    字节序

    JavaScript也有操作二进制的一天:聊ArrayBuffer和Blob

    • 大端字节序:高位字节在前,低位字节在后,这是人类读写数值的习惯顺序;
    • 小端字节序:低位字节在前,高位字节在后;

    计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的。所以,计算机的内部处理都是小端字节序。但是,人类还是习惯读写大端字节序。所以,除了计算机的内部处理,其他的场合几乎都是大端字节序,比如网络传输和文件储存。(计算机内部都是使用小端字节这点不严谨,有人说是因为不同公司的习惯而已,因为X86和ARM架构是使用小端,但IBM的PowerPC是用大端,但这里不深究)

    一般向外部写入数据是不需要管什么字节序的,直接用本机字节序即可,因为被写入的设备会有对应的驱动去判断字节序并正确读取数据。

    ArrayBuffer

    ArrayBuffer对象用来表示通用的、固定长度的原始数据缓冲区,是一个普通的JavaScript构造函数,可用于内存中分配特定数量的字节空间。ArrayBuffer本身是可读不可写的,只是一个数据容器

        const buf = new ArrayBuffer(16) // 在内存中分配16字节
        console.log(buf.byteLength) // 16
    

    ArrayBuffer和JavaScript数组在使用上是完全不同的,有三个区别:

    • ArrayBuffer初始化后是固定大小的,并且可读不可写
    • 数组里面可以放数字、字符串、布尔值以及对象和数组等,ArrayBuffer放0和1组成的二进制数据;
    • ArrayBuffer放在中,而Array放在中;

    TypeArray

    TypeArray是一个统称,实际使用的是特定元素类型的类型化数组构造函数;

        const typedArray1 = new Int8Array(8);
        typedArray1[0] = 32;
        
        console.log(typedArray1);
        // Int8Array [32, 0, 0, 0, 0, 0, 0, 0] 
        
        // 总共有
        Int8Array(); 
        Uint8Array(); 
        Uint8ClampedArray();
        Int16Array(); 
        Uint16Array();
        Int32Array(); 
        Uint32Array(); 
        Float32Array(); 
        Float64Array();
    

    TypeArray操作的数组成员都必须是同一个数据类型。每一种视图的构造函数,都有一个BYTES_PER_ELEMENT属性,表示这种数据类型占据的字节数。

        Int8Array.BYTES_PER_ELEMENT // 1
        Uint8Array.BYTES_PER_ELEMENT // 1
        Uint8ClampedArray.BYTES_PER_ELEMENT // 1
        Int16Array.BYTES_PER_ELEMENT // 2
        Uint16Array.BYTES_PER_ELEMENT // 2
        Int32Array.BYTES_PER_ELEMENT // 4
        Uint32Array.BYTES_PER_ELEMENT // 4
        Float32Array.BYTES_PER_ELEMENT // 4
        Float64Array.BYTES_PER_ELEMENT // 8
    

    由于视图的构造函数可以指定起始位置和长度,所以在同一段内存之中,可以依次生成不同类型的视图,这叫做“复合视图”。

        const buffer = new ArrayBuffer(24);
        
        const idView = new Uint32Array(buffer, 0, 1);
        const usernameView = new Uint8Array(buffer, 4, 16);
        const amountDueView = new Float32Array(buffer, 20, 1);
    

    二进制数组与字符串可以通过TextDecoder和TextEncoder来互相转换:

        let uint8Array = new Uint8Array([72, 101, 108, 108, 111]);
        alert( new TextDecoder().decode(uint8Array) ); // Hello
        
        let uint8Array = new TextEncoder();.encode("Hello");
        alert( uint8Array ); // 72,101,108,108,111
    

    DataView

    专为文件I/O和网络I/O设计,对缓冲数据有高度的控制,但比其他视图性能差一点。跟TypeArray不同,DataView视图中允许存在多种类型,并且可以声明数据的字节序。

    const buffer = new ArrayBuffer(4);
    
    const view1 = new DataView(buffer);
    
    // 在不同位置设置不同类型数字
    view1.setInt8(0, 42); 
    view1.setInt16(1, 22)
    
    console.log(view1.getInt8(0)) // 42
    console.log(view1.getInt16(1)) // 22
    

    如果一次读取两个或两个以上字节,就必须明确数据的存储方式,到底是小端字节序还是大端字节序。默认情况下,DataView的get方法使用大端字节序解读数据;

        // 小端字节序
        const v1 = dv.getUint16(1, true);
        
        // 大端字节序
        const v2 = dv.getUint16(3, false);
        
        // 大端字节序
        const v3 = dv.getUint16(3);
    

    Blob和ArratBuffer

    • Blob实际上就是针对文件设计出来的对象,而ArratBuffer针对需要传输的数据本身;
    • Blob主要解决媒体类型(MIME)的问题,ArratBuffer解决的是数据类型问题;
    • Blob是浏览器的api,ArratBuffer数据JavaScript中的标准,ArratBuffer是更底层的API,可以直接操作内存;

    二进制数组操作场景

    • 与底层显卡/外部设备进行二进制数据交互;
    • 利用SharedArrayBuffer在不同worker间共享内存(SharedArrayBuffer是ArrayBuffer的变体)
    • ...

    如有错误,请务必留言告知,多谢~


    下载网 » JavaScript也有操作二进制的一天:聊ArrayBuffer和Blob

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元