OffscreenCanvas—mempercepat operasi kanvas Anda dengan pekerja web

Tim Dresser

Kanvas adalah cara populer menggambar berbagai jenis grafik di layar dan titik masuk ke dunia WebGL. Dapat digunakan untuk menggambar bentuk, gambar, menjalankan animasi, atau bahkan menampilkan dan memproses konten video. SQL sering digunakan untuk menciptakan pengalaman pengguna yang indah di aplikasi web yang kaya media dan {i>game<i} {i>online<i}.

Dapat dibuat dengan skrip, artinya konten yang digambar di kanvas dapat dibuat secara terprogram, misalnya dalam JavaScript. Hal ini memberi kanvas fleksibilitas tinggi.

Pada saat yang sama, di {i>website<i} modern, eksekusi skrip adalah salah satu cara yang paling sumber masalah responsivitas pengguna. Karena logika dan rendering kanvas terjadi di thread yang sama dengan interaksi pengguna, komputasi (yang kadang berat) yang digunakan dalam animasi dapat membahayakan fungsi dan kinerja yang dirasakan.

Untungnya, OffscreenCanvas adalah respons terhadap ancaman tersebut.

Dukungan Browser

  • 69
  • 79
  • 105
  • 16,4

Sumber

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

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

Terlebih lagi, ia dapat digunakan di Web Worker, meskipun tidak ada DOM tersedia. Hal ini memungkinkan semua jenis kasus penggunaan yang menarik.

Menggunakan OffscreenCanvas dalam pekerja

Pekerja merupakan utas versi web—thread memungkinkan Anda menjalankan tugas di latar belakang.

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

OffscreenCanvas tidak bergantung pada DOM, sehingga dapat digunakan. Contoh berikut menggunakan OffscreenCanvas untuk menghitung warna gradien dalam 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 )

Berhenti memblokir rangkaian pesan utama

Memindahkan penghitungan yang berat ke pekerja memungkinkan Anda mengosongkan resource signifikan di thread utama. Gunakan transferControlToOffscreen untuk mencerminkan kanvas reguler ke instance OffscreenCanvas. Operasi yang diterapkan pada 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 ketika tema warna berubah—tema warna memakan waktu beberapa milidetik bahkan pada desktop yang cepat. Anda dapat memilih untuk menjalankan animasi di thread utama atau pada pekerja. Dalam kasus thread utama, Anda tidak dapat berinteraksi dengan tombol saat thread sedang berjalan—thread diblokir. Untuk pekerja, tidak ada dampak pada Responsivitas UI.

Demo

Cara ini juga berfungsi dengan cara lain: thread utama yang sibuk tidak memengaruhi animasi yang berjalan di seorang pekerja. Anda dapat menggunakan fitur ini untuk menghindari jank visual dan menjamin animasi yang lancar pada traffic thread utama, seperti ditunjukkan dalam demo berikut.

Demo

Dalam kasus kanvas biasa, animasi akan berhenti ketika thread utama terlalu banyak bekerja, sementara OffscreenCanvas berbasis pekerja bermain dengan lancar.

Karena OffscreenCanvas API umumnya kompatibel dengan Elemen Canvas reguler, Anda dapat menggunakannya sebagai {i>progressive enhancement<i}, juga dengan beberapa {i>library<i} grafis terkemuka di pasar.

Misalnya, Anda dapat mendeteksi fitur 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});

Yang salah di sini adalah Three.js mengharapkan kanvas untuk memiliki properti style.width dan style.height. OffscreenCanvas, karena terlepas sepenuhnya dari DOM, tidak memilikinya, jadi Anda harus menyediakannya sendiri, baik dengan menghentikannya atau memberikan logika yang mengikat nilai-nilai ini dengan dan kanvas.

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

Demo

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

Jika Anda banyak memanfaatkan kemampuan grafis kanvas, OffscreenCanvas dapat memengaruhi performa aplikasi. Meningkatkan ketersediaan konteks rendering kanvas bagi pekerja paralelisme di aplikasi web dan memanfaatkan sistem multi-core dengan lebih baik.

Referensi lainnya