ArrayBuffers służą do transportowania danych nieprzetworzonych i są używane przez kilka nowych interfejsów API, w tym WebSockets, Web Intents 2](https://www.html5rocks.com/en/tutorials/file/xhr2/) i WebWorkers. Jednak ponieważ pojawiły się one niedawno w świecie JavaScriptu, czasami są źle interpretowane lub używane w niewłaściwy sposób.
Semantycznie ArrayBuffer to po prostu tablica bajtów wyświetlana za pomocą określonej maski.
Ta maska, czyli instancja ArrayBufferView, określa, jak bajty są dopasowywane do oczekiwanej struktury treści. Jeśli na przykład wiesz, że bajty w ArrayBuffer reprezentują tablicę 16-bitowych liczb całkowitych bez znaku, wystarczy owinąć ArrayBuffer w widoku Uint16Array
i można manipulować jego elementami za pomocą nawiasów tak, jakby Uint16Array
była tablicą liczb całkowitych:
// 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]
Jednym z częstych praktycznych pytań dotyczących ArrayBuffer jest to, jak zamienić tablicę String
na tablicę ArrayBuffer
i odwrotnie. Ponieważ ArrayBuffer jest w istocie tablicą bajtów, ta konwersja wymaga, aby obie strony uzgodniły sposób reprezentowania znaków w ciągu znaków jako bajtów. Prawdopodobnie widzisz tę „umowę” po raz kolejny: jest to kodowanie znaków ciągu tekstowego (a standardowe „warunki umowy” to na przykład Unicode UTF-16 i iso8859-1). Zakładając, że uzgodniono kodowanie UTF-16, kod konwersji może wyglądać tak:
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;
}
Uwaga: Uint16Array
. To widok ArrayBuffer, który wyrównuje bajty ArrayBuffers jako elementy 16-bitowe. Nie obsługuje kodowania znaków, które jest traktowane jako Unicode przez tagi String.fromCharCode
i str.charCodeAt
.
Popularne pytanie na StackOverflow dotyczące tego zagadnienia
ma odpowiedź, która uzyskała wiele głosów. Zawiera ona nieco zawiłe rozwiązanie dotyczące konwersji: utwórz obiektFileReader
, który będzie pełnić funkcję konwertera, i przekaż mu obiekt Blob
zawierający ciąg znaków. Chociaż ta metoda działa, jest ona słabo czytelna i prawdopodobnie powolna. Ponieważ nieuzasadnione podejrzenia były przyczyną wielu błędów w historii ludzkości, zastosujmy tu bardziej naukowe podejście. jsperf'ed the two methods, a wynik potwierdza moje podejrzenia. Tutaj możesz obejrzeć wersję demonstracyjną.
W Chrome 20 użycie kodu manipulacji bezpośredniej ArrayBuffer
opisanego w tym artykule jest prawie 27 razy szybsze niż użycie metody FileReader
/Blob
.