Os ArrayBuffers são usados para transportar dados brutos, e várias APIs novas dependem deles, incluindo WebSockets, Intents da Web 2](https://www.html5rocks.com/en/tutorials/file/xhr2/) e WebWorkers. No entanto, como chegaram recentemente ao mundo do JavaScript, às vezes eles são mal interpretados ou usados indevidamente.
Semanticamente, um ArrayBuffer
é simplesmente uma matriz de bytes visualizados 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ê sabe que os bytes
em um ArrayBuffer representam uma matriz de números inteiros não assinados de 16 bits, basta unir
o ArrayBuffer em uma visualização de Uint16Array
e manipular seus elementos
usando a sintaxe de colchetes como se 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 "acordo" antes: é a
codificação de caracteres da string (e os "termos do acordo" usuais são, por
exemplo, Unicode UTF-16 e iso8859-1). Desse modo, supondo que você e a outra parte concordem com a 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
. Essa é uma visualização de ArrayBuffer que alinha bytes dos
ArrayBuffers como elementos de 16 bits. Ele não processa a codificação de caracteres, que é processada como Unicode por String.fromCharCode
e
str.charCodeAt
.
Uma
pergunta sobre isso (link em inglês)
conhecida no StackOverflow tem uma resposta muito votada com uma solução um pouco complicada para a conversão:
criar um FileReader
para atuar como um conversor e alimentar um Blob
contendo a
String. Embora esse método funcione, ele tem baixa legibilidade, e
sinto que ele seja lento. Como suspeitas infundadas geraram muitos erros na
história da humanidade, vamos adotar uma abordagem mais científica aqui. Eu
jsperf'ed os dois métodos
e o resultado confirma minha suspeita, e você confira a demonstração aqui.
No Chrome 20, é quase 27 vezes mais rápido usar o código de manipulação ArrayBuffer
direta neste artigo do que usar o método FileReader
/Blob
.