Los ArrayBuffers se usan para transportar datos sin procesar y varias API nuevas los usan, como WebSockets, Web Intents 2](https://www.html5rocks.com/en/tutorials/file/xhr2/) y WebWorkers. Sin embargo, debido a que llegaron recientemente al mundo de JavaScript, a veces se malinterpretan o se usan de forma inadecuada.
Semánticamente, un ArrayBuffer es simplemente un array de bytes vistos a través de una máscara específica.
Esta máscara, una instancia de ArrayBufferView, define cómo se alinean los bytes para que coincidan con la estructura esperada del contenido. Por ejemplo, si sabes que los bytes de un ArrayBuffer representan un array de números enteros sin firma de 16 bits, solo debes unir el ArrayBuffer a una vista Uint16Array
y manipular sus elementos con la sintaxis de corchetes como si la Uint16Array
fuera un array de números enteros:
// 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 pregunta práctica común sobre ArrayBuffer es cómo convertir un String
en ArrayBuffer
, y viceversa. Dado que un ArrayBuffer es, de hecho, un array de bytes, esta conversión requiere que ambos extremos acuerden cómo representar los caracteres de la string como bytes. Es probable que ya hayas visto este “acuerdo” antes: es la codificación de caracteres de la string (y los “términos del acuerdo” habituales son, por ejemplo, Unicode UTF-16 e iso8859-1). Por lo tanto, si tú y la otra parte acordaron la codificación UTF-16, el código de conversión podría ser similar al siguiente:
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;
}
Observa el uso de Uint16Array
. Esta es una vista de ArrayBuffer que alinea los bytes de ArrayBuffers como elementos de 16 bits. No controla la codificación de caracteres en sí, que String.fromCharCode
y str.charCodeAt
la manejan como Unicode.
Una pregunta sobre esto popular de Stack Overflow tiene una respuesta muy votada con una solución en cierta medida para la conversión: crea un FileReader
para que actúe como conversor y envíale un Blob
que contenga la cadena. Aunque este método funciona, tiene mala legibilidad y sospecho que es lento. Dado que las sospechas infundadas generaron muchos errores en la historia de la humanidad, adoptemos un enfoque más científico. Ya
jsperfé los dos métodos,
y el resultado confirma mi sospecha. Puedes consultar la demostración aquí.
En Chrome 20, es casi 27 veces más rápido usar el código de manipulación ArrayBuffer
directo en este artículo que usar el método FileReader
/Blob
.