iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0

ArrayBuffer 大概是 Transferable objects 中最常見的一種了,雖然也是矩陣,但不同於一般使用的 ArrayArrayBuffer 用來創建底層的原始二進制資料,並且常跟 WebGL 搭配使用。WebGL 允許瀏覽器能夠直接使用 GPU 進行 3D 的圖形渲染,在這過程中需要大量且即時的二進位制資料交換,但這並不是一般的 Array 所擅長的,所以才需要使用 ArrayBuffer

ArrayBuffer 代表在記憶體中原始的二進位制資料,以下程式碼產生 32 bytes,初始值為 0 的一段記憶體區塊:

const buffer = new ArrayBuffer(32);

但創建出來的 ArrayBuffer 無法直接被使用,它只是先分配一塊記憶體空間出來,後續操作的話需要使用到 ViewArray

ViewArray

分為兩種,負責拿來對 ArrayBuffer 進行各種操作 (ex. arr.push()arr.length 等)

  • TypedArray
    總共有11種類型,各種類型分別拿來操作不同的資料型態,例如 Uint8Array 代表矩陣中的每個元素是無符號8位整數(數值落在 0 ~255 之間)
  • DataView
    可以自定義不同的格式類型,例如:第一個 byte 是 Uint8 (無符號8位整數)、第二個 byte 可以是 Float32 (32位浮點數)。

https://ithelp.ithome.com.tw/upload/images/20230922/20162687tTLK9mjf2K.png
TypedArray 的 11 種類型 (From MDN)

建立 TypedArray

以下程式碼建立了 4 筆 Int16Array 型別的資料,而每個 Int16Array 元素又都佔據了 2 bytes,所以總共創建出 8 bytes 記憶體空間的資料

const i16 = new Int16Array(4); // 4 * 2 = 8 bytes
console.log(i16.byteLength); // 8

從 ArrayBuffer 建立 TypedArray

另外也可以從 ArrayBuffer 建立 TypedArray,佔據記憶體的空間會是由 ArrayBuffer 所決定

const buffer = new ArrayBuffer(4);
const i32 = new Int32Array(buffer); // 4 bytes
console.log(i32.byteLength); // 4

使用 DataView 創建不同元素類型的矩陣

使用 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 處理二進位資料 可以收穫豐盛。

補充小知識

  1. 一般使用的 Array 與 ArrayBuffer 之間的區別
    最一開始我們提到 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. 這一段是我根據不同地方找到的資料加上個人理解所寫出,如果有錯的話再請幫忙指正,謝謝)

Reference

ECMAScript 6 入门(第三版)ArrayBuffer
使用 JavaScript 處理二進位資料
[V8 Deep Dives] Understanding Array Internals
从Chrome源码看JS Array的实现
JavaScript 陣列的進化與效能分析


上一篇
可轉移的物件 - Transferable objects
下一篇
Transferable objects - MessagePort (Channel messaging)
系列文
網頁的另一個大腦:從基礎到進階掌握 Web Worker 技術30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言