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

Chrome 13 đã ra mắt tính năng gửi ArrayBuffer đến/từ một Web Worker bằng thuật toán có tên là sao chép 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 có các kiểu phức tạp như đối tượng File, Blob, ArrayBuffer và 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 sau của Firefox.

Càng nhanh càng tốt

Sao chép có cấu trúc rất hữu ích, nhưng vẫn là một thao tác sao chép. Chi phí truyền ArrayBuffer 32 MB đến một Worker có thể lên đến hàng trăm mili giây. Các phiên bản mới của trình duyệt có một cải tiến lớn về hiệu suất cho việc truyền thông báo, được gọi là Đối tượng có thể chuyển.

Với đối tượng có thể chuyển, dữ liệu được chuyển từ ngữ cảnh này sang ngữ cảnh khác. Đây là công cụ không sao chép, giúp cải thiện đáng kể hiệu suất gửi dữ liệu cho Worker. Hãy coi đây là mã tham chiếu nếu bạn thuộc thế giới C/C++. Tuy nhiên, không giống như tính năng truyền qua tham chiếu, "phiên bản" trong ngữ cảnh gọi sẽ không còn dùng được 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 còn sử dụng được nữa. Nội dung của ứng dụng này (theo đúng nghĩa đen) được chuyển sang ngữ cảnh Worker.

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

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 được chuyển. Trong ví dụ này, bạn cần 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 khi có thể chuyển dữ liệu, tôi đã tổng hợp bản minh hoạ.

Bản minh hoạ sẽ gửi ArrayBuffer 32 MB đến một worker và ngược lại bằng postMessage(). Nếu trình duyệt của bạn không hỗ trợ tính năng có thể chuyển, mẫu sẽ quay lại dùng tính năng sao chép có cấu trúc. Trung bình 5 lần chạy trong các trình duyệt khác nhau, đây là kết quả tôi đã nhận được:

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

Trên MacBook Pro/10,6,8/2,53 GHz/Intel Core 2 Duo, FF là nhanh nhất sử dụng nhân bản 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 lên luồng chính (RRT – Round Trip Time). So sánh với kết quả có thể chuyển, cùng một thử nghiệm mất 6,6 mili giây. Quả là một thành tích đáng nể!

Việc có các loại tốc độ này cho phép kết cấu/lưới WebGL khổng lồ được truyền liền mạch 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 hơi phức tạp trong trường hợp này. Bạn nên gửi một ArrayBuffer nhỏ cho worker của mình. Nếu vùng đệm được chuyển mà không được sao chép, .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 đang sử dụng 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 với cửa sổ và worker. Cập nhật (03/11/2016): Xóa tiền tố nhà cung cấp và đoạn mã cập nhật