目录
三、Blob、TypedArray和ArrayBuffer的互相转换
4、ArrayBuffer to Uint8数组(8位(1字节大小)的无符号整数数组)
7、获取/设置ArrayBuffer对应的数值(使用TypedArray作为视图来进行修改)
TypedArray是描述表达二进制数据的一种类数组数据视图,但并没有一个叫TypedArray的直接构造器。所以,属于TypedArray的子类有以下,其均可用于构造以及相关的类数组操作
注意,TypedArray既然是类数组,就具有类数组的相关特性,比如可以读取length、按索引读取、切片读取等等方法,但是不可以使用 push 或者 pop函数【JS中的类数组有函数中的隐式传参arguments、浏览器中节点NodeList、字符串String、TypedArray】
ArrayBuffer对象用来表示通用的原始二进制数据缓冲区。它是一个字节数组,是一个可转移对象(Transferable Object),但是它不可以直接操作其中的内容,而是要通过转换为TypedArray或者DataView(一种对象视图接口)再来进行读写操作。
构造函数的形式
new ArrayBuffer(length, options)
length代表数组缓冲区的大小(以字节为单位),options 代表一个对象,包含属性maxByteLength即数组缓冲区可以调整到的最大大小(以字节为单位)
返回的ArrayBuffer对象中内容初始化为0
【大小最好不超过1GB,减少内存溢出的风险】
byteLength:返回数组缓冲区的长度
detached:访问器,看是否将该实例从底层内存中分离,即转移实例
const buffer = new ArrayBuffer(8);
console.log(buffer.detached); // false,未转移实例
const newBuffer = buffer.transfer();
console.log(buffer.detached); // true,转移后的旧实例detached
console.log(newBuffer.detached); // false
maxByteLength
?:返回该数组缓冲区可调整到的最大长度const buffer1 = new ArrayBuffer(8, { maxByteLength: 16 });
const buffer2 = new ArrayBuffer(8);
console.log(buffer1.resizable);
// Expected output: true
console.log(buffer2.resizable);
// Expected output: false
ArrayBuffer.isView(); // false
ArrayBuffer.isView([]); // false
ArrayBuffer.isView({}); // false
ArrayBuffer.isView(null); // false
ArrayBuffer.isView(undefined); // false
ArrayBuffer.isView(new ArrayBuffer(10)); // false
ArrayBuffer.isView(new Uint8Array()); // true
ArrayBuffer.isView(new Float32Array()); // true
ArrayBuffer.isView(new Int8Array(10).subarray(0, 3)); // true
const buffer = new ArrayBuffer(2);
const dv = new DataView(buffer);
ArrayBuffer.isView(dv); // true
const buffer = new ArrayBuffer(8, { maxByteLength: 16 });
console.log(buffer.byteLength);
// Expected output: 8
buffer.resize(12);
console.log(buffer.byteLength);
// Expected output: 12
ArrayBuffer存在的意义是方便开发人员可以直接对自动内存进行管理。
例如,在JS中创建变量时,引擎会去计算当前这是什么类型的变量以及如何在内存中表示它。因为计算的过程需要耗费时间及内存空间,JS引擎通常会保留比变量真正需要的空间更多的空间。而且由于变量的不同,内存所消耗的空间可能比需要的大2到8倍,这可能导致大量的内存浪费。
此外,某些创建和使用JS对象的模式会使垃圾的回收变得非常困难。如果您正在执行手动内存管理,可以按需选择一种适合您的用例分配和取消分配策略
转换关系总结:
?Blob
?<->?ArrayBuffer
?<->?TypeArray
?<—->?Array
/* websocket的情况下二进制流的获取 */
var svip = 'ws://127.0.0.1:8080';
var ws = new WebSocket(svip);
ws.binaryType = 'arraybuffer'
ws.onmessage = function (e) {
var message = e.data;
}
var bl = new Blob(); // bl是要转换的blob
var fr = new FileReader();
fr.onload = function(){
var ab = this.result; // ab是转换后的结果
}
fr.readAsArrayBuffer(bl); //用reader,以arrayBuffer的形式读出
var ab = new ArrayBuffer(32);
var blob = new Blob([ab]); // 注意必须包裹[]
var ab = arrayBuffer; // arrayBuffer为要转换的值
var u8 = new Uint8Array(ab);
typedArray中的buffer通过.buffer属性获取
var u8 = new Uint8Array();
var ab = u8.buffer; // ab即是u8对应的arrayBuffer
这样转换出来的数组,可以让Blob中的文件内容进行正常的读写操作
var arr = [0x01,0x02,0x00,0x00,0x00,0x00,0x03];
var u8 = new Uint8Array(arr);
var blob=new Blob([u8],{type:'image/png'})
一串ArrayBuffer是可以被“理解”为很多个值的,以下面这个值为例,
按照服务端的协议,这串数据流的格式如下:
1 unsign byte (1字节) + 1 unsign int (4字节) + 1 unsign short (2字节)
解析方法如下,注意buffer中解析起点的索引符合TypedArray的读写大小单位
var arr = [0x01,0x02,0x00,0x00,0x00,0x00,0x03];
var u8 = new Uint8Array(arr);
var ab = u8.buffer;
console.log(ab); // ab为要解析的ArrayBuffer
var u8 = new Uint8Array(ab, 0, 1); // (arraybuffer, 字节解析的起点, 解析的长度)
var val_byte = u8[0];
console.log(val_byte);
// 解析unsign int
// 由于Uint32Array的解析起点必须是4的整数倍,而在流中该数据的起点是1,所以选择先“裁剪”(slice)出要解析的流片段,再用Uint32去解析该片段
var u32buff = ab.slice(1, 5);
var u32 = new Uint32Array(u32buff);
var val_uint = u32[0];
console.log(val_uint);
// 解析unsign short
var u16buff = ab.slice(5, 7);
var u16 = new Uint16Array(u16buff);
var val_short = u16[0];
console.log(val_short);
可以用Array.from或者TypedArray.from实现互转