Os ArrayBuffers são usados para transportar dados brutos, e várias novas APIs dependem deles, incluindo WebSockets, Web Intents 2](https://www.html5rocks.com/en/tutorials/file/xhr2/) e WebWorkers. No entanto, como eles chegaram recentemente ao mundo do JavaScript, às vezes são mal interpretados ou usados indevidamente.
Semanticamente, um ArrayBuffer
é simplesmente uma matriz de bytes visualizada por uma máscara específica.
Essa máscara, uma instância de
ArrayBufferView,
define como os bytes são alinhados para corresponder
à estrutura esperada do conteúdo. Por exemplo, se você souber que os bytes
em um ArrayBuffer representam uma matriz de números inteiros não assinados de 16 bits, basta agrupar
o ArrayBuffer em uma visualização Uint16Array
e manipular os elementos
usando a sintaxe de colchetes como se o Uint16Array
fosse uma matriz de números inteiros:
// 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]
Uma pergunta prática comum sobre ArrayBuffer é como converter um String
em
um ArrayBuffer
e vice-versa. Como um ArrayBuffer é, na verdade, uma matriz de bytes,
essa conversão exige que as duas extremidades concordem sobre como representar os caracteres
na string como bytes. Você provavelmente já viu esse "contrato" antes: ele é
a codificação de caracteres da string (e os "termos do contrato" usuais são, por
exemplo, Unicode UTF-16 e iso8859-1). Assim, supondo que você e a outra parte
concordaram na codificação UTF-16, o código de conversão pode ser algo como:
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;
}
Observe o uso de Uint16Array
. Esta é uma visualização de ArrayBuffer que alinha bytes de
ArrayBuffers como elementos de 16 bits. Ele não processa a codificação de caracteres
em si, que é processada como Unicode por String.fromCharCode
e
str.charCodeAt
.
Uma pergunta sobre isso
no StackOverflow tem uma resposta com muitos votos com uma solução um tanto complicada para a conversão:
crie um FileReader
para atuar como um conversor e alimente um Blob
contendo a
string. Embora esse método funcione, ele tem baixa legibilidade e
provavelmente é lento. Como suspeitas infundadas causaram muitos erros na
história da humanidade, vamos adotar uma abordagem mais científica. Testei os dois métodos com jsperf,
e o resultado confirma minha suspeita. Confira a demonstração aqui.
No Chrome 20, o código de manipulação ArrayBuffer
direto é quase 27 vezes mais rápido do que o método FileReader
/Blob
.