OffscreenCanvas—mempercepat operasi kanvas Anda dengan pekerja web

Tim Dresser

Kanvas adalah cara populer untuk menggambar semua jenis grafik di layar dan titik entri ke dunia WebGL. API ini dapat digunakan untuk menggambar bentuk, gambar, menjalankan animasi, atau bahkan menampilkan dan memproses konten video. API ini sering digunakan untuk menciptakan pengalaman pengguna yang menarik di aplikasi web yang kaya media dan game online.

Canvas dapat dibuat skrip, yang berarti konten yang digambar di kanvas dapat dibuat secara terprogram, misalnya, dalam JavaScript. Hal ini memberikan fleksibilitas yang besar pada kanvas.

Pada saat yang sama, di situs modern, eksekusi skrip adalah salah satu masalah responsivitas pengguna yang paling sering terjadi. Karena logika dan rendering kanvas terjadi pada thread yang sama dengan interaksi pengguna, komputasi (terkadang berat) yang terlibat dalam animasi dapat membahayakan performa yang sebenarnya dan yang dirasakan aplikasi.

Untungnya, OffscreenCanvas adalah respons terhadap ancaman tersebut.

Dukungan Browser

  • Chrome: 69.
  • Edge: 79.
  • Firefox: 105.
  • Safari: 16.4.

Sumber

Sebelumnya, kemampuan menggambar kanvas terikat dengan elemen <canvas>, yang berarti bergantung langsung pada DOM. OffscreenCanvas, seperti namanya, memisahkan DOM dan Canvas API dengan memindahkannya ke luar layar.

Berkat pemisahan ini, rendering OffscreenCanvas sepenuhnya terlepas dari DOM dan karenanya menawarkan beberapa peningkatan kecepatan dibandingkan kanvas biasa karena tidak ada sinkronisasi di antara keduanya.

Namun, yang lebih penting adalah bahwa DOM dapat digunakan di Web Worker, meskipun tidak ada DOM yang tersedia. Hal ini memungkinkan berbagai kasus penggunaan yang menarik.

Menggunakan OffscreenCanvas di pekerja

Pekerja adalah versi thread web—yang memungkinkan Anda menjalankan tugas di latar belakang.

Memindahkan beberapa skrip ke pekerja akan memberi aplikasi Anda lebih banyak ruang untuk melakukan tugas penting bagi pengguna di thread utama. Tanpa OffscreenCanvas, tidak ada cara untuk menggunakan Canvas API di pekerja, karena tidak ada DOM yang tersedia.

OffscreenCanvas tidak bergantung pada DOM, sehingga dapat digunakan. Contoh berikut menggunakan OffscreenCanvas untuk menghitung warna gradien di pekerja:

// 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 )

Membatalkan pemblokiran thread utama

Memindahkan penghitungan berat ke pekerja memungkinkan Anda mengosongkan resource yang signifikan di thread utama. Gunakan metode transferControlToOffscreen untuk mencerminkan kanvas biasa ke instance OffscreenCanvas. Operasi yang diterapkan ke OffscreenCanvas akan dirender di kanvas sumber secara otomatis.

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

Pada contoh berikut, penghitungan berat terjadi saat tema warna berubah—penghitungan ini akan memerlukan waktu beberapa milidetik bahkan di desktop yang cepat. Anda dapat memilih untuk menjalankan animasi di thread utama atau di pekerja. Untuk thread utama, Anda tidak dapat berinteraksi dengan tombol saat tugas berat berjalan—thread diblokir. Dalam kasus pekerja, tidak ada dampak pada responsivitas UI.

Demo

Hal ini juga berfungsi sebaliknya: thread utama yang sibuk tidak memengaruhi animasi yang berjalan di pekerja. Anda dapat menggunakan fitur ini untuk menghindari jank visual dan menjamin animasi yang lancar meskipun ada traffic thread utama, seperti yang ditunjukkan dalam demo berikut.

Demo

Untuk kanvas reguler, animasi akan berhenti saat thread utama dipaksa bekerja secara berlebihan, sedangkan OffscreenCanvas berbasis pekerja akan diputar dengan lancar.

Karena OffscreenCanvas API umumnya kompatibel dengan Elemen Kanvas biasa, Anda dapat menggunakannya sebagai peningkatan progresif, juga dengan beberapa library grafis terkemuka di pasar.

Misalnya, Anda dapat mendeteksi fiturnya dan jika tersedia, gunakan dengan Three.js dengan menentukan opsi kanvas di konstruktor perender:

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});

Satu hal yang perlu diperhatikan di sini adalah Three.js mengharapkan kanvas memiliki properti style.width dan style.height. OffscreenCanvas, yang sepenuhnya terlepas dari DOM, tidak memilikinya, sehingga Anda harus menyediakannya sendiri, baik dengan membuat stub atau memberikan logika yang mengaitkan nilai ini dengan dimensi kanvas asli.

Berikut ini cara menjalankan animasi Three.js dasar di pekerja:

Demo

Perhatikan bahwa beberapa API terkait DOM tidak tersedia di pekerja, jadi jika Anda ingin menggunakan fitur Three.js yang lebih canggih seperti tekstur, Anda mungkin memerlukan lebih banyak solusi. Untuk beberapa ide tentang cara mulai bereksperimen dengan hal ini, lihat video dari Google I/O 2017.

Jika Anda banyak menggunakan kemampuan grafis kanvas, OffscreenCanvas dapat memengaruhi performa aplikasi Anda secara positif. Membuat konteks rendering kanvas tersedia untuk pekerja akan meningkatkan paralelisme dalam aplikasi web dan memanfaatkan sistem multi-core dengan lebih baik.

Referensi lainnya