Đối tượng có thể chuyển được – Nhanh như chớp

Chrome 13 đã giới thiệu tính năng gửi ArrayBuffer đến/từ một Worker trên web bằng thuật toán có tên là nhân bản có cấu trúc. Điều này cho phép API postMessage() chấp nhận các thông báo không chỉ là chuỗi mà còn là các loại phức tạp như File, Blob, ArrayBuffer và đối tượng JSON. Tính năng sao chép có cấu trúc cũng được hỗ trợ trong các phiên bản Firefox mới hơn.

Càng nhanh càng tốt

Tính năng sao chép có cấu trúc rất tuyệt vời, nhưng vẫn là một thao tác sao chép. Mức hao tổn khi truyền ArrayBuffer 32 MB cho một Worker có thể lên đến hàng trăm mili giây. Các phiên bản trình duyệt mới có cải thiện đáng kể về hiệu suất khi truyền thông báo, được gọi là Đối tượng có thể chuyển.

Với các đối tượng có thể chuyển, dữ liệu sẽ được chuyển từ ngữ cảnh này sang ngữ cảnh khác. Phương thức này không sao chép, giúp cải thiện đáng kể hiệu suất gửi dữ liệu đến Worker. Hãy coi đây là truyền tham chiếu nếu bạn đến từ thế giới C/C++. Tuy nhiên, không giống như truyền tham chiếu, "phiên bản" từ ngữ cảnh gọi sẽ không còn sau khi được chuyển sang ngữ cảnh mới. Ví dụ: khi chuyển ArrayBuffer từ ứng dụng chính sang Worker, ArrayBuffer ban đầu sẽ bị xoá và không thể sử dụng được nữa. Nội dung của lớp này (theo nghĩa đen) được chuyển sang ngữ cảnh Worker.

Để chơi với các đối tượng có thể chuyển, có một phiên bản postMessage() mới hỗ trợ các đối tượng có thể chuyển:

worker.postMessage(arrayBuffer, [transferableList]);
window.postMessage(arrayBuffer, targetOrigin, [transferableList]);

Đối với trường hợp worker, đối số đầu tiên là thông báo ArrayBuffer. Đối số thứ hai là danh sách các mục cần chuyển. Trong ví dụ này, bạn sẽ chỉ định arrayBuffer trong danh sách có thể chuyển.

Bản minh hoạ điểm chuẩn

Để xem mức tăng hiệu suất của các thành phần có thể chuyển, tôi đã tạo một bản minh hoạ.

Bản minh hoạ này gửi ArrayBuffer 32 MB đến một worker và trả về bằng postMessage(). Nếu trình duyệt của bạn không hỗ trợ các đối tượng có thể chuyển, thì mẫu sẽ quay lại phương thức nhân bản có cấu trúc. Sau đây là kết quả tôi nhận được khi chạy trung bình 5 lần trên các trình duyệt khác nhau:

Biểu đồ so sánh tính năng sao chép có cấu trúc với đối tượng có thể chuyển

Trên MacBook Pro/10.6.8/2.53 GHz/Intel Core 2 Duo, FF là phương thức nhanh nhất khi sử dụng tính năng sao chép có cấu trúc. Trung bình, mất 302 mili giây để gửi ArrayBuffer 32 MB đến một worker và đăng lại worker đó vào luồng chính (RRT – Thời gian đi và về). So với các giá trị có thể chuyển, cùng một thử nghiệm này mất 6,6 mili giây. Đó là một mức tăng hiệu suất rất lớn!

Với những tốc độ này, bạn có thể truyền liền mạch các hoạ tiết/lưới WebGL khổng lồ giữa Worker và ứng dụng chính.

Phát hiện tính năng

Việc phát hiện tính năng này sẽ hơi khó khăn. Bạn nên gửi một ArrayBuffer nhỏ đến worker. Nếu vùng đệm được chuyển chứ không được sao chép, thì .byteLength của vùng đệm đó sẽ chuyển về 0:

var ab = new ArrayBuffer(1);
worker.postMessage(ab, [ab]);
if (ab.byteLength) {
    alert('Transferables are not supported in your browser!');
} else {
    // Transferables are supported.
}

Hỗ trợ: Hiện tại là Chrome 17 trở lên, Firefox, Opera, Safari và IE10 trở lên

Đã cập nhật (13/12/2011): Đoạn mã để hiển thị chữ ký webkitPostMessage() khác nhau đối với cửa sổ và worker. Cập nhật (03/11/2016): Xoá tiền tố nhà cung cấp và cập nhật đoạn mã