ArrayBuffer 是什麼
ArrayBuffer 物件用來表示通用的、固定長度的原始二進位制資料緩衝區。
它是一個位元組陣列,通常在其他語言中稱為“byte array”。
你不能直接操作 ArrayBuffer 的內容,而是要通過型別陣列物件或 DataView 物件來操作,它們會將緩衝區中的資料表示為特定的格式,並通過這些格式來讀寫緩衝區的內容。
簡單用法
const buffer = new ArrayBuffer(8);
console.log(buffer.byteLength); // 8
length 大於 Number.MAX_SAFE_INTEGER(>= 2 53)或為負數,則丟擲一個 RangeError 異常。**
作用
從XHR、File API、Canvas, WebGL 等等各種地方,讀取了一大串位元組流,如果用JS裡的Array去存,又浪費,又低效
於是為了配合這些新的API增強JS的二進位制處理能力,就有了ArrayBuffer
建立 ArrayBuffer 的時候,就相當於申請了一塊記憶體, 不能(也不方便)直接用它
所以也就有了 TypedArray, 比如 Uint32Array,Int16Array , Int8Array, Float32Array 等等等等
這些就是用來操作 TypedArray 的具體實現
TypeArray
一個型別化陣列(TypedArray)物件描述了一個底層的二進位制資料緩衝區(binary data buffer)的一個類陣列檢視(view)。事實上,沒有名為 TypedArray 的全域性屬性,也沒有一個名為 TypedArray 的建構函式。相反,有許多不同的全域性屬性,它們的值是特定元素型別的型別化陣列建構函式,如下所示
// 下面程式碼是語法格式,不能直接執行,
// TypedArray 關鍵字需要替換為底部列出的建構函式。
new TypedArray(); // ES2017中新增
new TypedArray(length);
new TypedArray(typedArray);
new TypedArray(object);
new TypedArray(buffer [, byteOffset [, length]]);
// TypedArray 指的是以下的其中之一:
Int8Array();
Uint8Array();
Uint8ClampedArray();
Int16Array();
Uint16Array();
Int32Array();
Uint32Array();
Float32Array();
Float64Array();
- Unit8Array 指的是,把 ArrayBuffer 的每個 byte(8-bit) 當作一個單獨的無符號整型數字 (0 - 255)
- Unit16Array 表示為使用 16 bits (2 bytes) 表示一個無符號整型 (0 ~ 2^16-1) 的數的陣列
- Int8Array 表示使用 8 bits 表示一個有符號整型 (-128 ~ 127)
- Float32Array 表示使用 32 bits 表示一個浮點數
- Unit7ClampedArray 在 0 ~ 255 範圍內和 Unit8Array 是一樣的,對超出範圍的處理有所不同,和影像處理相關(一般畫素範圍也是 0 ~ 255)
使用場景:
檔案的轉換:
arrayBuffer 可以轉換為 Blob 物件:
const blob = new Blob([arrayBuffer],{type:"xxx/xxx"});
Blob 轉換為 arrayBuffer:
const fileReader:FileReader = new FileReader();
fileReader.addEventListener("load",(event)=>{
const arrayBuffer = event.target.result;
//...
})
fileReader.readAsArrayBuffer(file);
或者:
const arrayBuffer = await file.arrayBuffer();
從 ajax 獲取:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'xxxxx');
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status == 200) {
const arrayBuffer = xhr.response;
}
};
xhr.send();
例子 1
音訊的某一種播放方法
const audioContext = new AudioContext();
const buffer = await file.arrayBuffer();
const auidoBuffer = await audioContext.decodeAudioData(buffer);
const source = audioContext.createBufferSource();
source.buffer = auidoBuffer;
source.connect(audioContext.destination);
source.start();
例子 2
讀取二進位制檔案
// HTML 程式碼如下
// <input type="file" onchange="typefile(this.files[0])"></input>
function typefile(file) {
// 檔案開頭的四個位元組,生成一個 Blob 物件
let slice = file.slice(0, 4);
let reader = new FileReader();
// 讀取這四個位元組
reader.readAsArrayBuffer(slice);
reader.onload = function (e) {
let buffer = reader.result;
// 將這四個位元組的內容,視作一個32位整數
let view = new DataView(buffer);
let magic = view.getUint32(0, false);
// 根據檔案的前四個位元組,判斷它的型別
switch(magic) {
case 0x89504E47: file.verified_type = 'image/png'; break;
case 0x47494638: file.verified_type = 'image/gif'; break;
case 0x25504446: file.verified_type = 'application/pdf'; break;
case 0x504b0304: file.verified_type = 'application/zip'; break;
}
console.log(file.name, file.verified_type);
};
}
總結
這裡還有很多東西沒講, 比如 SharedArrayBuffers
, 大小端問題等等, 想要深入的話可以自行了解
在前端使用到 buffer 的場景確實非常少見, 但涉及到比較底層或者偏門一點點的時候就會看到他了, 這個時候也要求我們要了解他, 比如檔案, canvas, WebGL, WASM, EXCEL 處理