ArrayBuffer in TypeScript

ArrayBuffer in TypeScript

Dit artikel legt ArrayBuffer in TypeScript uit.

We leggen ArrayBuffer in TypeScript stap voor stap uit, van de basis tot praktische technieken.

YouTube Video

ArrayBuffer in TypeScript

ArrayBuffer is een ingebouwd object dat een 'ruw geheugenoppervlak' voor binaire gegevens weergeeft. Het vertegenwoordigt een ruwe buffer van vaste lengte, waarop TypedArray of DataView worden geplaatst voor lezen en schrijven.

Basisprincipes en kenmerken van ArrayBuffer

ArrayBuffer is een bytevolgorde met een vaste lengte. Je geeft de grootte in bytes op bij het aanmaken, en de lengte kan daarna niet meer worden gewijzigd.

1// Create a new ArrayBuffer of 16 bytes.
2const buf = new ArrayBuffer(16);
3console.log(buf.byteLength); // 16
  • Deze code maakt een lege buffer van 16 bytes aan. Je kunt de grootte controleren met byteLength.

TypedArray en DataView — Weergaven voor het manipuleren van buffers

ArrayBuffer heeft niet de mogelijkheid om gegevens te lezen of te schrijven. Daarom worden feitelijke bewerkingen uitgevoerd via TypedArray of DataView, waarbij je bij het benaderen van gegevens types zoals gehele getallen of drijvende-kommagetallen en endianness specificeert.

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 is een bytegerichte array-weergave en kan als een normale array worden benaderd. Als je meerdere weergaven op hetzelfde ArrayBuffer plaatst, delen ze hetzelfde geheugen voor lezen en schrijven.

DataView: Lezen en schrijven op willekeurige grenzen en met gespecificeerde endianheid

DataView is handig voor fijnmazig lezen en schrijven per byte, en je kunt hierbij little of big endian specificeren.

 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 stelt je in staat om waarden te lezen en te schrijven door offset in het geheugen op te geven, waardoor het geschikt is voor het implementeren van protocollen die netwerk-bytevolgorde vereisen.

Conversie tussen tekst en ArrayBuffer (TextEncoder / TextDecoder)

Gebruik TextEncoder en TextDecoder om tekst naar binair om te zetten en omgekeerd.

 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 retourneert een Uint8Array, dus als je een ArrayBuffer nodig hebt, moet je naar de .buffer-eigenschap verwijzen. Met de slice-methode kun je de benodigde gegevens extraheren door offset en lengte op te geven.

Slicing en kopiëren van ArrayBuffer

De slice-methode retourneert een nieuwe ArrayBuffer. ArrayBuffer kan niet van grootte worden veranderd; als aanpassen van de grootte nodig is, maak dan een nieuwe buffer aan en kopieer de gegevens erin.

 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
  • Omdat de slice-methode een nieuwe ArrayBuffer retourneert, kun je, als je efficiëntie of het delen van referenties prioriteert, de subarray-methode van TypedArray gebruiken om naar dezelfde buffer te verwijzen.

Verschil tussen TypedArray.subarray en kopiëren

De subarray van TypedArray geeft een nieuwe weergave die naar hetzelfde ArrayBuffer verwijst.

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]
  • Gedeelde weergaven kunnen de kosten van kopiëren vermijden, maar omdat ze naar dezelfde buffer verwijzen, moet je voorzichtig zijn met bijwerkingen.

Buffers samenvoegen (meerdere ArrayBuffers combineren)

Aangezien ArrayBuffer een vaste lengte heeft, moet je om meerdere buffers te combineren een nieuw ArrayBuffer aanmaken en de gegevens kopiëren.

 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]
  • Als je vaak grote hoeveelheden gegevens samenvoegt, is het efficiënter om de totale grootte vooraf te berekenen en slechts één keer een nieuwe buffer toe te wijzen, zoals in deze code.

ArrayBuffer doorgeven aan een Worker (Transferable)

In de postMessage-functie van de browser kun je een ArrayBuffer als een “overdraagbaar” object overdragen. Eigenaarschap kan zonder kopiëren worden overgedragen, waardoor de kosten van het kopiëren worden vermeden.

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
  • Door de over te dragen objecten in een array als tweede argument van postMessage op te geven, kun je eigenaarschap van overdraagbare objecten zoals ArrayBuffer zonder kopiëren overdragen.
  • Na de overdracht wordt de buffer aan de oorspronkelijke kant 'losgekoppeld' en is deze niet meer toegankelijk. Het gebruik van SharedArrayBuffer maakt gelijktijdige toegang vanuit meerdere threads mogelijk, maar het gebruik ervan brengt beveiligingseisen en omgevingsbeperkingen met zich mee.

Gebruik in Node.js (conversie met Buffer)

In Node.js kun je converteren tussen het binaire type Buffer van Node.js en ArrayBuffer. Dit is handig bij het ontwikkelen voor zowel browsers als Node.js met 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) in Node.js maakt meestal een kopie, maar er zijn gevallen waarbij verwijzingsdeling mogelijk is, dus let goed op de offsets.

Prestatieoverwegingen en best practices

Om de prestaties te optimaliseren en ArrayBuffer efficiënt te verwerken, zijn er enkele belangrijke punten om te onthouden. Hieronder noemen en verklaren we praktische best practices.

  • Verminder het aantal kopieën Gebruik bij het verwerken van grote binaries subarray (gedeelde weergave) of transferables om het aantal kopieën te beperken.

  • Wijs grote buffers in één keer toe Het herhaaldelijk toewijzen van kleine buffers verhoogt de overhead. Wijs indien mogelijk in één keer een grote buffer toe en gebruik daaruit gedeelten naar behoefte.

  • Specificeer endianness expliciet Gebruik bij het verwerken van multibyte-waarden altijd DataView en specificeer expliciet de endianheid. Big-endian is vaak de standaard bij netwerkprotocollen.

Veelvoorkomende toepassingsvoorbeelden

ArrayBuffer wordt veel gebruikt in zowel browsers als Node.js.

  1. Parsen en opbouwen van binaire protocollen (header-informatie verwerken met DataView)
  2. Mediaverwerking, zoals beeld- en audiogegevens (fetch(...).then(res => res.arrayBuffer()))
  3. Gedeeld geheugen voor WebAssembly (Wasm-geheugen werkt op basis van ArrayBuffer)
  4. Zware bewerkingen uitbesteden aan Workers (door ArrayBuffer als transferable door te geven)

De volgende code is een voorbeeld voor het verkrijgen en analyseren van binaire gegevens.

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}
  • Deze code haalt binaire gegevens op van een willekeurige URL in de browser en toont de eerste paar bytes. De code laadt gegevens die via de fetch API zijn opgehaald als een ArrayBuffer en bekijkt de eerste 16 bytes met een Uint8Array.

Samenvatting

ArrayBuffer is een representatie van ruw geheugen, waarmee efficiënte binaire bewerkingen via TypedArray en DataView mogelijk zijn. Door onnodig kopiëren te vermijden en endianheid expliciet te specificeren, kun je veilige en snelle binaire verwerking realiseren.

Je kunt het bovenstaande artikel volgen met Visual Studio Code op ons YouTube-kanaal. Bekijk ook het YouTube-kanaal.

YouTube Video