ArrayBuffer dalam TypeScript

ArrayBuffer dalam TypeScript

Artikel ini menjelaskan tentang ArrayBuffer dalam TypeScript.

Kami akan menjelaskan ArrayBuffer dalam TypeScript secara bertahap, mulai dari dasar hingga teknik praktis.

YouTube Video

ArrayBuffer dalam TypeScript

ArrayBuffer adalah objek bawaan yang merepresentasikan “area memori mentah” untuk data biner. Ini merepresentasikan buffer mentah dengan panjang tetap, di mana TypedArray atau DataView digunakan untuk membaca dan menulis data.

Konsep Dasar dan Karakteristik ArrayBuffer

ArrayBuffer adalah urutan byte dengan panjang tetap. Anda menentukan ukuran dalam byte saat membuatnya, dan panjangnya tidak dapat diubah setelah itu.

1// Create a new ArrayBuffer of 16 bytes.
2const buf = new ArrayBuffer(16);
3console.log(buf.byteLength); // 16
  • Kode ini membuat buffer kosong dengan ukuran 16 byte. Anda dapat memeriksa ukuran buffer menggunakan byteLength.

TypedArray dan DataView — Tampilan untuk Memanipulasi Buffer

ArrayBuffer tidak memiliki kemampuan untuk membaca atau menulis data. Oleh karena itu, operasi sebenarnya dilakukan melalui TypedArray atau DataView, dengan menentukan tipe seperti bilangan bulat atau bilangan pecahan serta endianness saat mengakses data.

1// Create a buffer and a Uint8Array view over it. Then write bytes and read them.
2const buffer = new ArrayBuffer(8);
3const u8 = new Uint8Array(buffer);
4
5u8[0] = 0x41; // 'A'
6u8[1] = 0x42; // 'B'
7console.log(u8); // Uint8Array(8) [ 65, 66, 0, 0, 0, 0, 0, 0 ]
  • Uint8Array adalah tampilan array byte dan dapat diakses seperti array biasa. Jika Anda menempatkan beberapa tampilan pada ArrayBuffer yang sama, mereka berbagi memori yang sama untuk membaca dan menulis.

DataView: Membaca dan Menulis pada Batas serta Endianness yang Fleksibel

DataView berguna untuk membaca dan menulis data per byte secara rinci, serta memungkinkan Anda menentukan little atau big endian.

 1// Using DataView to write/read multi-byte values with endianness control.
 2const buf2 = new ArrayBuffer(8);
 3const view = new DataView(buf2);
 4
 5// Write a 32-bit integer (little-endian)
 6view.setInt32(0, 0x12345678, true);
 7
 8// Read it back as little-endian and big-endian
 9const little = view.getInt32(0, true);
10const big = view.getInt32(0, false);
11console.log(little.toString(16)); // "12345678"
12console.log(big.toString(16));    // "78563412"
  • DataView memungkinkan Anda untuk membaca dan menulis nilai dengan menentukan offset di memori, sehingga cocok untuk mengimplementasikan protokol yang memerlukan penanganan urutan byte jaringan.

Konversi antara String dan ArrayBuffer (TextEncoder / TextDecoder)

Untuk mengubah teks menjadi biner dan sebaliknya, gunakan TextEncoder dan TextDecoder.

 1// Convert string -> ArrayBuffer and back using TextEncoder/TextDecoder.
 2const encoder = new TextEncoder();
 3const decoder = new TextDecoder();
 4
 5// Unicode escape sequences
 6const str = "\u3053\u3093\u306B\u3061\u306F";
 7const encoded = encoder.encode(str); // Uint8Array
 8console.log(encoded); // Uint8Array([...])
 9
10// If you need an ArrayBuffer specifically:
11const ab = encoded.buffer.slice(encoded.byteOffset, encoded.byteOffset + encoded.byteLength);
12console.log(ab.byteLength); // bytes length of encoded text
13
14// Decode back
15const decoded = decoder.decode(encoded);
16console.log(decoded);
  • TextEncoder.encode mengembalikan Uint8Array, jadi jika Anda memerlukan ArrayBuffer, Anda harus mengacu pada properti .buffer. Dengan metode slice, Anda dapat mengekstrak data yang diperlukan dengan menentukan offset dan panjangnya.

Memotong dan Menyalin ArrayBuffer

Metode slice mengembalikan ArrayBuffer yang baru. ArrayBuffer tidak dapat diubah ukurannya; jika perlu mengubah ukuran, buat buffer baru dan salin datanya ke dalamnya.

 1// Slice an ArrayBuffer and copy to a new sized buffer.
 2const original = new Uint8Array([1,2,3,4,5]).buffer;
 3const part = original.slice(1, 4); // bytes 1..3
 4console.log(new Uint8Array(part)); // Uint8Array [ 2, 3, 4 ]
 5
 6// Resize: create a new buffer and copy existing content
 7const larger = new ArrayBuffer(10);
 8const target = new Uint8Array(larger);
 9target.set(new Uint8Array(original), 0);
10console.log(target); // first bytes filled with original data
  • Karena metode slice mengembalikan ArrayBuffer baru, jika Anda mengutamakan efisiensi atau berbagi referensi, Anda dapat menggunakan metode subarray dari TypedArray untuk mengacu pada buffer yang sama.

Perbedaan antara TypedArray.subarray dan Penyalinan

subarray milik TypedArray mengembalikan tampilan baru yang merujuk pada ArrayBuffer yang sama.

1// subarray shares the same underlying buffer; modifying one affects the other.
2const arr = new Uint8Array([10,20,30,40]);
3const viewSub = arr.subarray(1,3); // shares memory
4viewSub[0] = 99;
5console.log(arr); // Uint8Array [10, 99, 30, 40]
  • Tampilan bersama dapat menghindari biaya penyalinan, namun karena mereka mengacu pada buffer yang sama, Anda perlu berhati-hati terhadap efek samping.

Menggabungkan Buffer (Mengombinasikan beberapa ArrayBuffer)

Karena ArrayBuffer memiliki panjang tetap, untuk menggabungkan beberapa buffer buat ArrayBuffer baru dan salin datanya.

 1// Concatenate multiple ArrayBuffers
 2function concatBuffers(buffers: ArrayBuffer[]): ArrayBuffer {
 3  const total = buffers.reduce((sum, b) => sum + b.byteLength, 0);
 4  const result = new Uint8Array(total);
 5  let offset = 0;
 6  for (const b of buffers) {
 7    const u8 = new Uint8Array(b);
 8    result.set(u8, offset);
 9    offset += u8.length;
10  }
11  return result.buffer;
12}
13
14const a = new Uint8Array([1,2]).buffer;
15const b = new Uint8Array([3,4,5]).buffer;
16const c = concatBuffers([a, b]);
17console.log(new Uint8Array(c)); // [1,2,3,4,5]
  • Jika Anda sering menggabungkan sejumlah besar data, menghitung ukuran total terlebih dahulu dan mengalokasikan buffer baru hanya sekali, seperti pada kode ini, akan lebih efisien.

Mengirimkan ArrayBuffer ke Worker (Transferable)

Dalam postMessage browser, Anda dapat mentransfer sebuah ArrayBuffer sebagai objek "transferable". Kepemilikan dapat dipindahkan tanpa penyalinan, sehingga menghindari biaya penyalinan.

1// Example: posting an ArrayBuffer to a Worker as a transferable object (browser)
2const worker = new Worker('worker.js');
3const bufferToSend = new Uint8Array([1,2,3,4]).buffer;
4
5// Transfer ownership to the worker (main thread no longer owns it)
6worker.postMessage(bufferToSend, [bufferToSend]);
7
8// After transfer, bufferToSend.byteLength === 0 in many browsers (detached)
9console.log(bufferToSend.byteLength); // may be 0
  • Dengan menentukan objek yang akan ditransfer dalam sebuah array sebagai argumen kedua untuk postMessage, Anda dapat memindahkan kepemilikan objek transferable seperti ArrayBuffer tanpa menyalin.
  • Setelah transfer, buffer menjadi "detached" di sisi asal dan tidak dapat diakses. Penggunaan SharedArrayBuffer memungkinkan akses simultan dari beberapa thread, tetapi penggunaannya memiliki persyaratan keamanan dan pembatasan lingkungan.

Penanganan di Node.js (Konversi dengan Buffer)

Di Node.js, Anda dapat mengonversi antara tipe biner Buffer dan ArrayBuffer. Ini berguna jika Anda menargetkan baik browser maupun Node.js dengan TypeScript.

 1// Convert ArrayBuffer <-> Node.js Buffer
 2// In Node.js environment:
 3const ab = new Uint8Array([10,20,30]).buffer;
 4const nodeBuffer = Buffer.from(ab); // ArrayBuffer -> Buffer
 5console.log(nodeBuffer); // <Buffer 0a 14 1e>
 6
 7const backToAb = nodeBuffer.buffer.slice(
 8    nodeBuffer.byteOffset,
 9    nodeBuffer.byteOffset + nodeBuffer.byteLength
10);
11console.log(new Uint8Array(backToAb)); // Uint8Array [10,20,30]
  • Buffer.from(arrayBuffer) di Node.js biasanya membuat salinan, tetapi ada kasus di mana referensi dapat dibagi, jadi perhatikan offset-nya.

Pertimbangan Performa dan Praktik Terbaik

Untuk mengoptimalkan performa dan menangani ArrayBuffer secara efisien, ada beberapa hal penting yang perlu diperhatikan. Di bawah ini, kami daftar dan jelaskan praktik terbaik secara praktis.

  • Kurangi Jumlah Penyalinan Saat menangani data biner besar, gunakan subarray (tampilan bersama) atau transferable untuk mengurangi penyalinan.

  • Alokasikan Buffer Besar Sekaligus Mengalokasikan buffer kecil secara berulang meningkatkan overhead. Jika memungkinkan, alokasikan buffer besar sekaligus dan gunakan bagiannya sesuai kebutuhan.

  • Tentukan Endianness Secara Eksplisit Saat menangani nilai multibyte, gunakan DataView dan secara eksplisit tentukan endianness-nya. Big-endian sering digunakan sebagai standar untuk protokol jaringan.

Contoh Kasus Penggunaan Umum

ArrayBuffer banyak digunakan baik di browser maupun Node.js.

  1. Parsing dan membangun protokol biner (memproses informasi header dengan DataView)
  2. Pemrosesan media seperti data gambar dan audio (fetch(...).then(res => res.arrayBuffer()))
  3. Memori bersama untuk WebAssembly (memori Wasm beroperasi berdasarkan ArrayBuffer)
  4. Mengalihkan pemrosesan berat ke Worker (mengirim ArrayBuffer sebagai transferable)

Kode berikut adalah contoh mendapatkan dan menganalisis data biner.

1// Example: fetch binary data in browser and inspect first bytes
2async function fetchAndInspect(url: string) {
3  const resp = await fetch(url);
4  const ab = await resp.arrayBuffer();
5  const u8 = new Uint8Array(ab, 0, Math.min(16, ab.byteLength));
6  console.log('first bytes:', u8);
7}
  • Kode ini mengambil data biner dari URL mana pun di browser dan menampilkan beberapa byte pertama. Kode ini memuat data yang diambil melalui API fetch sebagai ArrayBuffer dan memeriksa 16 byte pertama menggunakan Uint8Array.

Ringkasan

ArrayBuffer adalah representasi memori mentah, memungkinkan operasi biner yang efisien melalui TypedArray dan DataView. Dengan merancang agar menghindari penyalinan yang tidak perlu dan secara eksplisit menentukan endianness, Anda dapat mencapai pemrosesan biner yang aman dan berkinerja tinggi.

Anda dapat mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Silakan periksa juga saluran YouTube kami.

YouTube Video