Gli ArrayBuffer vengono utilizzati per trasportare i dati non elaborati e diverse nuove API si basano su questi oggetti, tra cui WebSockets, Web Intents 2](https://www.html5rocks.com/en/tutorials/file/xhr2/) e WebWorkers. Tuttavia, poiché sono state introdotte di recente nel mondo di JavaScript, a volte vengono interpretate o utilizzate in modo errato.
Dal punto di vista semantico, un ArrayBuffer è semplicemente un array di byte visualizzato tramite una maschera specifica.
Questa maschera, un'istanza di
ArrayBufferView,
definisce in che modo i byte vengono allineati in modo da corrispondere
alla struttura prevista dei contenuti. Ad esempio, se sai che i byte
in un ArrayBuffer rappresentano un array di interi non firmati a 16 bit, basta avvolgere
l'ArrayBuffer in una vista Uint16Array
e puoi manipolarne gli elementi
utilizzando la sintassi delle parentesi graffe come se Uint16Array
fosse un array di interi:
// suppose buf contains the bytes [0x02, 0x01, 0x03, 0x07]
// notice the multibyte values respect the hardware endianess, which is little-endian in x86
var bufView = new Uint16Array(buf);
if (bufView[0]===258) { // 258 === 0x0102
console.log("ok");
}
bufView[0] = 255; // buf now contains the bytes [0xFF, 0x00, 0x03, 0x07]
bufView[0] = 0xff05; // buf now contains the bytes [0x05, 0xFF, 0x03, 0x07]
bufView[1] = 0x0210; // buf now contains the bytes [0x05, 0xFF, 0x10, 0x02]
Una domanda pratica comune su ArrayBuffer è come convertire un String
in un ArrayBuffer
e viceversa. Poiché un ArrayBuffer è in realtà un array di byte,
questa conversione richiede che entrambe le parti concordino su come rappresentare i caratteri
nella stringa come byte. Probabilmente hai già visto questo "contratto": si tratta della codifica dei caratteri della stringa (e i "termini del contratto" usuali sono, ad esempio, Unicode UTF-16 e iso8859-1). Pertanto, supponendo che tu e l'altra parte
abbiate concordato la codifica UTF-16, il codice di conversione potrebbe essere simile al seguente:
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint16Array(buf));
}
function str2ab(str) {
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i=0, strLen=str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
Nota l'utilizzo di Uint16Array
. Si tratta di una visualizzazione ArrayBuffer che allinea i byte degli ArrayBuffer come elementi a 16 bit. Non gestisce la codifica dei caratteri, che viene gestita come Unicode da String.fromCharCode
e str.charCodeAt
.
Una popolare domanda su questo argomento su Stack Overflow ha una risposta molto votata con una soluzione un po' complicata per la conversione: creare un FileReader
da utilizzare come convertitore e inviarvi un Blob
contenente la stringa. Sebbene questo metodo funzioni, ha una scarsa leggibilità e immagino sia lento. Poiché sospetti infondati hanno causato molti errori nella
storia dell'umanità, adottiamo un approccio più scientifico. Ho eseguito jsperf sui due metodi e il risultato conferma i miei sospetti. Dai un'occhiata alla demo qui.
In Chrome 20, è quasi 27 volte più veloce utilizzare il codice di manipolazione diretta di ArrayBuffer
riportato in questo articolo rispetto al metodo FileReader
/Blob
.