ArrayBuffer 大概是 Transferable objects
中最常見的一種了,雖然也是矩陣,但不同於一般使用的 Array
,ArrayBuffer
用來創建底層的原始二進制資料,並且常跟 WebGL 搭配使用。WebGL 允許瀏覽器能夠直接使用 GPU 進行 3D 的圖形渲染,在這過程中需要大量且即時的二進位制資料交換,但這並不是一般的 Array
所擅長的,所以才需要使用 ArrayBuffer
。
ArrayBuffer
代表在記憶體中原始的二進位制資料,以下程式碼產生 32 bytes,初始值為 0 的一段記憶體區塊:
const buffer = new ArrayBuffer(32);
但創建出來的 ArrayBuffer
無法直接被使用,它只是先分配一塊記憶體空間出來,後續操作的話需要使用到 ViewArray
。
分為兩種,負責拿來對 ArrayBuffer
進行各種操作 (ex. arr.push()
、arr.length
等)
Uint8Array
代表矩陣中的每個元素是無符號8位整數(數值落在 0 ~255 之間)
TypedArray 的 11 種類型 (From MDN)
以下程式碼建立了 4 筆 Int16Array
型別的資料,而每個 Int16Array
元素又都佔據了 2 bytes,所以總共創建出 8 bytes 記憶體空間的資料
const i16 = new Int16Array(4); // 4 * 2 = 8 bytes
console.log(i16.byteLength); // 8
另外也可以從 ArrayBuffer
建立 TypedArray
,佔據記憶體的空間會是由 ArrayBuffer
所決定
const buffer = new ArrayBuffer(4);
const i32 = new Int32Array(buffer); // 4 bytes
console.log(i32.byteLength); // 4
使用 DataView
的 get, set 等函式,可以創建不同類型資料的矩陣
const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);
view.setUint8(1, 255); // Max unsigned 8-bit integer
view.setUint16(1, 65535); // Max unsigned 16-bit integer
console.log(view.getUint8(1)); // 255
console.log(view.getUint16(1)); // 65535
我想介紹 ArrayBuffer
的優秀文章已經很多了,所以這邊只介紹了最基本的概念,讓大家對於文章範例中用到 ArrayBuffer
的地方不會太過陌生,關於更進階的像是 溢位(overflow)、ClampedArray、Endianness(Byte order) 等知識,推薦大家閱讀 使用 JavaScript 處理二進位資料 可以收穫豐盛。
ArrayBuffer
用來直接產生二進位制資料並用來快速與 WebGL 直接溝通,但為什麼一般的 Array
無法做到這件事呢?原因是一般 Array
無法直接操作記憶體分配的位置,在 Javascript v8 引擎 中建立 Array
時,事實上背後還有一連串複雜的算法,而這算法會在 Array
建立時,產生多餘的記憶體空間。// 假設我們想要產生一個 [42] 的矩陣:
// 一般 Array 產生方式
const arr = [];
arr.push(42);
// 使用 ArrayBuffer 產生
const buffer = new ArrayBuffer(1);
const bufferArr = new Uint8Array(buffer);
bufferArr[0] = 42;
我們知道下面由 ArrayBuffer
產生的矩陣,分配了 1 byte 的記憶體空間,但上面那個呢?根據 [V8 Deep Dives] Understanding Array Internals 這篇文章所做的測試,在 64 位元的電腦上,總共會佔據 17 * 8 = 136 bytes 的空間!想想光只是一個元素的矩陣,記憶體的差異就可以達到一百多倍,這樣當需要大量即時資料與 WebGL 溝通時將會多耗費資源。因此當牽涉到 WebGL 等 3D 運算的時候都是使用 ArrayBuffer
,避免記憶體空間的浪費。
(P.S. 這一段是我根據不同地方找到的資料加上個人理解所寫出,如果有錯的話再請幫忙指正,謝謝)
ECMAScript 6 入门(第三版)ArrayBuffer
使用 JavaScript 處理二進位資料
[V8 Deep Dives] Understanding Array Internals
从Chrome源码看JS Array的实现
JavaScript 陣列的進化與效能分析