TypedArray in TypeScript

TypedArray in TypeScript

Questo articolo spiega TypedArray in TypeScript.

Spiegheremo TypedArray in TypeScript, includendo esempi pratici.

YouTube Video

TypedArray in TypeScript

TypedArray è un meccanismo per gestire efficacemente i dati binari. È particolarmente utile per operazioni binarie a basso livello come dati di immagini di grandi dimensioni, flussi di byte di rete e array numerici per WebGL.

Come creare un ArrayBuffer

ArrayBuffer rappresenta una regione di byte di lunghezza fissa. Per prima cosa, crea un buffer e verifica la sua dimensione e la lunghezza in byte.

1// Create an ArrayBuffer of 16 bytes
2const buffer: ArrayBuffer = new ArrayBuffer(16);
3console.log("buffer.byteLength:", buffer.byteLength); // 16
  • Questo codice crea una regione vuota di 16 byte. ArrayBuffer di per sé non ha funzioni di lettura/scrittura, quindi vi si accede tramite TypedArray o DataView.

Tipi di TypedArray

Esistono molti tipi di TypedArray, ad esempio i seguenti. Questi variano a seconda del tipo di dato e della dimensione che gestiscono.

TypedArray Tipo di dato Dimensione in bit
Int8Array Intero a 8 bit 8 bit
Uint8Array Intero senza segno a 8 bit 8 bit
Uint8ClampedArray Intero senza segno a 8 bit limitato 8 bit
Int16Array Intero a 16 bit 16 bit
Uint16Array Intero senza segno a 16 bit 16 bit
Int32Array Intero a 32 bit 32 bit
Uint32Array Intero senza segno a 32 bit 32 bit
Float32Array Numero in virgola mobile a 32 bit 32 bit
Float64Array Numero in virgola mobile a 64 bit 64 bit

TypedArray di base (Uint8Array, Int16Array, Float32Array, ecc.)

TypedArray crea una 'vista tipizzata' sopra un ArrayBuffer. Di seguito sono riportati esempi di creazione e utilizzo di alcuni tipici TypedArray.

 1// Create a buffer and different typed views over it
 2const buf = new ArrayBuffer(8); // 8 bytes
 3
 4// Create views
 5const u8 = new Uint8Array(buf);    // 8 x uint8
 6const i16 = new Int16Array(buf);   // 4 x int16 (since each int16 is 2 bytes)
 7const f32 = new Float32Array(buf); // 2 x float32 (4 bytes each)
 8
 9console.log("Uint8 length:", u8.length);
10console.log("Int16 length:", i16.length);
11console.log("Float32 length:", f32.length);
  • Creando più viste sullo stesso ArrayBuffer, puoi leggere e scrivere la stessa memoria in tipi o granularità differenti. length della vista è il numero di elementi, mentre byteLength è il numero di byte.

Scrittura e lettura (operazioni a livello di byte)

Quando scrivi un valore in un TypedArray, i byte corrispondenti in memoria vengono aggiornati. Puoi vedere le modifiche leggendo lo stesso buffer con una vista diversa.

 1// Demonstrate writing via one view and reading via another
 2const buffer2 = new ArrayBuffer(4);
 3const u8view = new Uint8Array(buffer2);
 4const u32view = new Uint32Array(buffer2);
 5
 6u8view[0] = 0x78;
 7u8view[1] = 0x56;
 8u8view[2] = 0x34;
 9u8view[3] = 0x12;
10
11console.log("Uint8 bytes:", Array.from(u8view)); // [120, 86, 52, 18]
12console.log("Uint32 value (platform endianness):", u32view[0]); // value depends on endianness
  • In questo esempio, scriviamo una sequenza di byte e poi leggiamo la stessa area come un intero a 32 bit. Nota che l'output dipende dall’endianness dell’ambiente di esecuzione.

Endianness (ordine dei byte) e DataView

DataView è utile se vuoi controllare i problemi di endianness dipendenti dall’ambiente. DataView ti consente di specificare l’endianness durante la lettura e la scrittura.

 1// Use DataView to read/write with explicit endianness control
 2const b = new ArrayBuffer(4);
 3const dv = new DataView(b);
 4
 5// write little-endian 32-bit integer
 6dv.setUint32(0, 0x12345678, true);
 7
 8// read as little-endian and big-endian
 9const little = dv.getUint32(0, true);
10const big = dv.getUint32(0, false);
11
12console.log("little-endian read:", little.toString(16)); // "12345678"
13console.log("big-endian read:", big.toString(16));       // different value
  • DataView è un meccanismo conveniente per leggere e scrivere byte in dettaglio. Supporta diversi tipi, come interi con o senza segno e numeri in virgola mobile, permettendoti di specificare esplicitamente l’endianness (ordine dei byte), molto utile nell'implementazione di protocolli binari.

Differenza tra subarray e slice

Il metodo subarray di un TypedArray restituisce una vista che condivide il buffer originale, mentre slice restituisce una nuova copia. Le prestazioni e gli effetti collaterali variano a seconda di quale utilizzi.

1const base = new Uint8Array([1, 2, 3, 4, 5]);
2
3const shared = base.subarray(1, 4); // shares underlying buffer
4const copied = base.slice(1, 4);    // copies data
5
6shared[0] = 99;
7console.log("base after shared modification:", base); // shows change
8console.log("copied remains:", copied);              // unaffected
  • Se modifichi la vista condivisa, anche l’array originale cambierà, il che può causare effetti collaterali indesiderati. Se vuoi preservare in modo sicuro l’array originale, puoi crearne una copia in anticipo utilizzando slice().

Copia dei buffer e conversione di tipo (conversione tra TypedArray)

Spiegheremo come copiare i dati tra TypedArray e come incollare parti usando il metodo set.

 1// Copy and convert between typed arrays
 2const src = new Float32Array([1.5, 2.5, 3.5]);
 3const dst = new Uint16Array(src.length);
 4
 5// Convert by mapping (explicit conversion)
 6for (let i = 0; i < src.length; i++) {
 7  dst[i] = Math.round(src[i]); // simple conversion rule
 8}
 9console.log("converted dst:", Array.from(dst)); // [2, 2, 4]
10
11// Using set to copy bytes (requires compatible underlying buffer or same element type)
12const src2 = new Uint8Array([10, 20, 30]);
13const dst2 = new Uint8Array(6);
14dst2.set(src2, 2); // copy src2 into dst2 starting at index 2
15console.log("dst2 after set:", Array.from(dst2)); // [0,0,10,20,30,0]
  • Se i tipi degli elementi sono diversi, è necessario convertire i valori, ad esempio tramite arrotondamento o controllo dei limiti, invece di copiarli semplicemente. set consente una copia rapida tra TypedArray dello stesso tipo di elemento.

Esempio pratico: un parser di protocollo binario (implementazione semplice)

Qui introduciamo un esempio di parser semplice che legge un dato binario a formato fisso composto da un tipo di 1 byte, una lunghezza dati di 2 byte e un payload seguente.

 1// Simple binary message parser:
 2// format: [type: uint8][length: uint16 BE][payload: length bytes]
 3function parseMessages(buffer: ArrayBuffer) {
 4  const dv = new DataView(buffer);
 5  let offset = 0;
 6  const messages: { type: number; payload: Uint8Array }[] = [];
 7
 8  while (offset + 3 <= dv.byteLength) {
 9    const type = dv.getUint8(offset);
10    const length = dv.getUint16(offset + 1, false); // big-endian
11    offset += 3;
12    if (offset + length > dv.byteLength) break; // truncated
13    const payload = new Uint8Array(buffer, offset, length);
14    messages.push({ type, payload });
15    offset += length;
16  }
17
18  return messages;
19}
20
21// Example usage
22const buf = new ArrayBuffer(1 + 2 + 3 + 1 + 2 + 2); // two messages
23const dv = new DataView(buf);
24let off = 0;
25// first message: type=1, length=3, payload=[1,2,3]
26dv.setUint8(off, 1); dv.setUint16(off + 1, 3, false); off += 3;
27new Uint8Array(buf, off, 3).set([1, 2, 3]); off += 3;
28// second message: type=2, length=2, payload=[9,8]
29dv.setUint8(off, 2); dv.setUint16(off + 1, 2, false); off += 3;
30new Uint8Array(buf, off, 2).set([9, 8]);
31
32console.log(parseMessages(buf));
  • In questo esempio, l’intestazione viene letta usando DataView, e la sezione del payload è creata con Uint8Array. Il controllo dell’endianness e della lunghezza dei buffer è importante.

Web API e TypedArray (esempio: recupero di dati binari)

Questo è un esempio tipico di gestione di un ArrayBuffer ottenuto da una richiesta di rete tramite TypedArray.

 1// Example of fetching binary and mapping to typed array
 2async function fetchBinary(url: string) {
 3  const res = await fetch(url);
 4  const ab = await res.arrayBuffer();
 5  const view = new Uint8Array(ab);
 6  // process view...
 7  console.log("received bytes:", view.length);
 8  return view;
 9}
10
11// Usage (call in async context)
12// fetchBinary("/path/to/file.bin");
  • È possibile passare direttamente l’ArrayBuffer ottenuto con Response.arrayBuffer() a un TypedArray. Viene usato per immagini, audio o protocolli binari personalizzati.

Suggerimenti sulle prestazioni ed errori comuni

Ecco alcuni 'consigli sulle prestazioni' ed 'errori comuni' utili da conoscere nell’uso dei TypedArray:.

  • Evita copie non necessarie Per elaborare grandi quantità di dati in modo efficiente, puoi ridurre le copie non necessarie creando viste parziali con subarray o condividendo lo stesso ArrayBuffer tra più viste.

  • Fai attenzione all’endianness Per le comunicazioni di rete o nei formati di file, spesso viene specificato l’ordine dei dati (ordine dei byte). Utilizzare DataView permette di specificare esplicitamente l’endianness durante lettura e scrittura, evitando interpretazioni errate involontarie.

  • Fai attenzione agli intervalli di valori per ciascun tipo Ad esempio, Uint8 può rappresentare solo valori da 0 a 255. Se inserisci un valore negativo, possono verificarsi troncamenti o rollover dei valori, quindi dovresti definire delle regole di conversione secondo necessità.

  • Considera il carico sul garbage collector La creazione frequente di grandi ArrayBuffer aumenta il carico della gestione della memoria. In situazioni critiche per le prestazioni, potresti considerare di progettare il codice per riutilizzare i buffer esistenti il più possibile.

Riepilogo

TypedArray è un meccanismo per gestire dati binari in modo rapido ed efficiente. Combinando ArrayBuffer, che riserva un’area di byte a lunghezza fissa, con TypedArray o DataView, che leggono e scrivono il contenuto utilizzando tipi specifici, puoi eseguire operazioni binarie flessibili. A seconda del caso d’uso, puoi scegliere tra l’uso di subarray/slice o DataView, e progettare la tua implementazione prestando attenzione all’endianness e alle copie.

Puoi seguire l'articolo sopra utilizzando Visual Studio Code sul nostro canale YouTube. Controlla anche il nostro canale YouTube.

YouTube Video