ArrayBuffers được dùng để vận chuyển dữ liệu thô và một số API mới dựa vào các ArrayBuffer này, bao gồm cả WebSockets, Web Intents 2](https://www.html5rocks.com/en/tutorials/file/xhr2/) và WebWorkers. Tuy nhiên, vì các hàm này mới xuất hiện trong thế giới JavaScript, nên đôi khi chúng bị hiểu sai hoặc bị sử dụng sai.
Về mặt ngữ nghĩa, ArrayBuffer chỉ là một mảng byte được xem thông qua một mặt nạ cụ thể.
Mặt nạ này, một thực thể của ArrayBufferView, xác định cách các byte được căn chỉnh để khớp với cấu trúc dự kiến của nội dung. Ví dụ: nếu biết rằng các byte trong ArrayBuffer đại diện cho một mảng số nguyên không dấu 16 bit, bạn chỉ cần gói ArrayBuffer trong thành phần hiển thị Uint16Array
và có thể thao tác các phần tử của ArrayBuffer bằng cú pháp dấu ngoặc đơn như thể Uint16Array
là một mảng số nguyên:
// 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]
Một câu hỏi thực tế thường gặp về ArrayBuffer là làm cách nào để chuyển đổi String
thành ArrayBuffer
và ngược lại. Vì ArrayBuffer thực sự là một mảng byte, nên quá trình chuyển đổi này yêu cầu cả hai đầu đều đồng ý về cách biểu thị các ký tự trong Chuỗi dưới dạng byte. Bạn có thể đã thấy "thỏa thuận" này trước đây: đó là mã hoá ký tự của Chuỗi (và "điều khoản thoả thuận" thông thường là, ví dụ: Unicode UTF-16 và iso8859-1). Do đó, giả sử bạn và bên kia đã đồng ý về cách mã hoá UTF-16, mã chuyển đổi có thể có dạng như sau:
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;
}
Lưu ý cách sử dụng Uint16Array
. Đây là thành phần hiển thị ArrayBuffer giúp căn chỉnh các byte của ArrayBuffer dưới dạng phần tử 16 bit. Phương thức này không tự xử lý việc mã hoá ký tự, mà String.fromCharCode
và str.charCodeAt
sẽ xử lý dưới dạng Unicode.
Một câu hỏi phổ biến trên StackOverflow về vấn đề này có một câu trả lời được nhiều người bình chọn với giải pháp hơi phức tạp cho việc chuyển đổi: tạo một FileReader
để đóng vai trò là trình chuyển đổi và đưa một Blob
chứa Chuỗi vào đó. Mặc dù phương thức này hoạt động, nhưng khả năng đọc kém và tôi nghi ngờ rằng phương thức này sẽ chậm. Vì những nghi ngờ vô căn cứ đã dẫn đến nhiều sai lầm trong lịch sử nhân loại, nên chúng ta hãy áp dụng một phương pháp khoa học hơn ở đây. Tôi đã jsperf hai phương thức này và kết quả xác nhận sự nghi ngờ của tôi. Bạn có thể xem bản minh hoạ tại đây.
Trong Chrome 20, việc sử dụng mã thao tác ArrayBuffer
trực tiếp trong bài viết này nhanh hơn gần 27 lần so với việc sử dụng phương thức FileReader
/Blob
.