OffscreenCanvas – tăng tốc các hoạt động canvas của bạn bằng một trình thực thi web

Tim Dresser

Canvas là một cách phổ biến vẽ tất cả các loại đồ hoạ trên màn hình và một điểm đến để kết nối với thế giới WebGL. Công cụ này có thể được dùng để vẽ hình dạng, hình ảnh, chạy ảnh động hoặc thậm chí là hiển thị và xử lý nội dung video. Nó thường được sử dụng để tạo trải nghiệm người dùng đẹp trong các ứng dụng web đa phương tiện và trò chơi trực tuyến.

Có thể viết kịch bản, tức là nội dung được vẽ trên canvas có thể được tạo bằng cách lập trình, ví dụ: trong JavaScript. Điều này giúp canvas trở nên linh hoạt hơn.

Đồng thời, trên các trang web hiện đại, thực thi tập lệnh là một trong những cách các vấn đề liên quan đến các nguồn phản hồi của người dùng. Vì logic canvas và hiển thị xảy ra trên cùng một chuỗi với tương tác của người dùng, các phép tính (đôi khi phức tạp) liên quan đến ảnh động có thể gây hại cho và hiệu suất ước tính.

Rất may là OffscreenCanvas có thể được sử dụng. là một biện pháp phản hồi cho mối đe doạ đó.

Hỗ trợ trình duyệt

  • 69
  • 79
  • 105
  • 16,4

Nguồn

Trước đây, chức năng vẽ canvas gắn liền với phần tử <canvas>, tức là nó phụ thuộc trực tiếp vào DOM. OffscreenCanvas, đúng như tên gọi, tách DOM và Canvas API bằng cách di chuyển nó ra khỏi màn hình.

Nhờ hoạt động phân tách này, chế độ hiển thị OffscreenCanvas được tách hoàn toàn khỏi DOM và do đó, Google sẽ cải thiện một số điểm về tốc độ so với canvas thông thường vì không có sự đồng bộ hoá giữa hai tài khoản.

Tuy nhiên, hơn thế nữa là nó có thể được sử dụng trong Web Worker, ngay cả khi không có DOM có sẵn. Điều này cho phép tất cả các loại trường hợp sử dụng thú vị.

Sử dụng OffscreenCanvas trong một worker

Worker là phiên bản luồng trên web, cho phép bạn chạy các tác vụ trong nền.

Việc di chuyển một số tập lệnh của bạn sang một worker giúp ứng dụng của bạn có thêm không gian để thực hiện những công việc quan trọng với người dùng các tác vụ trên luồng chính. Nếu không có OffscreenCanvas, bạn sẽ không thể sử dụng API Canvas trong một trình thực thi, vì ở đó, không có DOM nào.

OffscreenCanvas không phụ thuộc vào DOM nên có thể sử dụng được. Ví dụ sau sử dụng OffscreenCanvas để tính toán màu gradient trong một worker:

// file: worker.js
function getGradientColor(percent) {
  const canvas = new OffscreenCanvas(100, 1);
  const ctx = canvas.getContext('2d');
  const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
  gradient.addColorStop(0, 'red');
  gradient.addColorStop(1, 'blue');
  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, ctx.canvas.width, 1);
  const imgd = ctx.getImageData(0, 0, ctx.canvas.width, 1);
  const colors = imgd.data.slice(percent * 4, percent * 4 + 4);
  return `rgba(${colors[0]}, ${colors[1]}, ${colors[2]}, ${colors[3]})`;
}

getGradientColor(40);  // rgba(152, 0, 104, 255 )

Bỏ chặn chuỗi chính

Chuyển phép tính phức tạp sang một worker cho phép bạn giải phóng các tài nguyên quan trọng trên luồng chính. Sử dụng transferControlToOffscreen để phản chiếu canvas thông thường sang một thực thể OffscreenCanvas. Các thao tác đã áp dụng cho Ngoài màn hình chính, Canvas sẽ tự động hiển thị trên canvas nguồn.

const offscreen = document.querySelector('canvas').transferControlToOffscreen();
const worker = new Worker('myworkerurl.js');
worker.postMessage({canvas: offscreen}, [offscreen]);

Trong ví dụ sau, phép tính phức tạp diễn ra khi chủ đề màu sắc thay đổi — công việc này sẽ mất vài mili giây ngay cả trên một máy tính để bàn nhanh. Bạn có thể chọn chạy ảnh động trên luồng chính hoặc trong worker. Trong trường hợp luồng chính, bạn không thể tương tác với nút này khi đang xử lý tác vụ đang chạy – luồng bị chặn. Trong trường hợp của worker, thì sẽ không có tác động nào đến Khả năng phản hồi của giao diện người dùng.

Bản minh hoạ

Nó cũng hoạt động theo cách khác: luồng chính bận không ảnh hưởng đến ảnh động đang chạy trên một worker. Bạn có thể sử dụng tính năng này để tránh hiện tượng giật hình ảnh và đảm bảo ảnh động mượt mà bất kể lưu lượng truy cập luồng chính, như minh hoạ trong bản minh hoạ sau.

Bản minh hoạ

Trong trường hợp canvas thông thường, ảnh động sẽ dừng khi luồng chính làm việc quá mức một cách giả tạo, trong khi OffscreenCanvas dựa trên worker hoạt động trơn tru.

Vì API OffscreenCanvas thường tương thích với Phần tử Canvas thông thường, nên bạn có thể sử dụng nó như một cải tiến tăng dần, đồng thời với một số thư viện đồ hoạ hàng đầu trên thị trường.

Ví dụ: bạn có thể phát hiện tính năng và sử dụng cùng với Three.js (nếu có) bằng cách chỉ định tuỳ chọn canvas trong hàm khởi tạo kết xuất đồ hoạ:

const canvasEl = document.querySelector('canvas');
const canvas =
  'OffscreenCanvas' in window
    ? canvasEl.transferControlToOffscreen()
    : canvasEl;
canvas.style = {width: 0, height: 0};
const renderer = new THREE.WebGLRenderer({canvas: canvas});

Vấn đề nhận được ở đây là Three.js dự kiến canvas sẽ có thuộc tính style.widthstyle.height. OffscreenCanvas, vì được tách biệt hoàn toàn khỏi DOM, không có tính năng này, vì vậy bạn cần tự cung cấp nó, bằng cách loại bỏ giá trị đó hoặc cung cấp logic liên kết các giá trị này với giá trị ban đầu kích thước canvas.

Sau đây là cách chạy ảnh động Three.js cơ bản trong một trình thực thi:

Bản minh hoạ

Hãy lưu ý rằng một số API liên quan đến DOM chưa có sẵn trong worker, vì vậy, nếu bạn muốn sử dụng các tính năng Three.js nâng cao hơn như hoạ tiết, bạn có thể cần nhiều giải pháp khác. Để có một số ý tưởng về cách bắt đầu thử nghiệm các giải pháp này, hãy xem video trình bày tại Google I/O 2017.

Nếu bạn chủ yếu dùng các tính năng đồ hoạ của canvas, thì OffscreenCanvas có thể tích cực sử dụng các tính năng đồ hoạ ảnh hưởng đến hiệu suất của ứng dụng. Việc cung cấp ngữ cảnh kết xuất canvas cho trình thực thi sẽ tăng lên tính song song trong các ứng dụng web và tận dụng tốt hơn hệ thống đa lõi.

Tài nguyên khác