Input masuk ke Compositor
Ini adalah bagian terakhir dari seri blog 4 bagian yang melihat ke dalam Chrome; menyelidiki cara Chrome menangani kode kita untuk menampilkan situs. Dalam postingan sebelumnya, kita telah melihat proses rendering dan mempelajari kompositor. Dalam postingan ini, kita akan melihat cara compositor memungkinkan interaksi yang lancar saat input pengguna masuk.
Peristiwa input dari sudut pandang browser
Saat mendengar "peristiwa input", Anda mungkin hanya memikirkan pengetikan di kotak teks atau klik mouse, tetapi dari sudut pandang browser, input berarti gestur apa pun dari pengguna. Scroll roda mouse adalah peristiwa input dan sentuh atau mouse over juga merupakan peristiwa input.
Saat gestur pengguna seperti sentuhan pada layar terjadi, proses browser adalah yang menerima
gestur pada awalnya. Namun, proses browser hanya mengetahui tempat gestur tersebut terjadi karena
konten di dalam tab ditangani oleh proses perender. Jadi, proses browser mengirimkan jenis
peristiwa (seperti touchstart
) dan koordinatnya ke proses perender. Proses perender menangani
peristiwa dengan tepat dengan menemukan target peristiwa dan menjalankan pemroses peristiwa yang terpasang.
Compositor menerima peristiwa input
Di postingan sebelumnya, kita telah melihat cara kompositor dapat menangani scroll dengan lancar dengan menggabungkan lapisan raster. Jika tidak ada pemroses peristiwa input yang dilampirkan ke halaman, thread Compositor dapat membuat frame komposit baru yang sepenuhnya independen dari thread utama. Namun, bagaimana jika beberapa pemroses peristiwa disertakan ke halaman? Bagaimana thread kompositor mengetahui apakah peristiwa perlu ditangani?
Memahami region yang tidak dapat di-scroll dengan cepat
Karena menjalankan JavaScript adalah tugas thread utama, saat halaman dikomposisi, thread kompositor akan menandai area halaman yang memiliki pengendali peristiwa yang dilampirkan sebagai "Area yang Tidak Dapat Di-scroll dengan Cepat". Dengan memiliki informasi ini, thread kompositor dapat memastikan untuk mengirim peristiwa input ke thread utama jika peristiwa terjadi di wilayah tersebut. Jika peristiwa input berasal dari luar region ini, thread komponer akan terus menyusun frame baru tanpa menunggu thread utama.
Perhatikan saat Anda menulis pengendali peristiwa
Pola penanganan peristiwa yang umum dalam pengembangan web adalah delegasi peristiwa. Karena peristiwa berbentuk balon, Anda dapat melampirkan satu pengendali peristiwa di elemen paling atas dan mendelegasikan tugas berdasarkan target peristiwa. Anda mungkin pernah melihat atau menulis kode seperti di bawah.
document.body.addEventListener('touchstart', event => {
if (event.target === area) {
event.preventDefault();
}
});
Karena Anda hanya perlu menulis satu pengendali peristiwa untuk semua elemen, ergonomi pola delegasi peristiwa ini menarik. Namun, jika Anda melihat kode ini dari sudut pandang browser, sekarang seluruh halaman ditandai sebagai area yang tidak dapat di-scroll dengan cepat. Artinya, meskipun aplikasi Anda tidak peduli dengan input dari bagian halaman tertentu, thread kompositor harus berkomunikasi dengan thread utama dan menunggunya setiap kali peristiwa input masuk. Dengan demikian, kemampuan scroll yang lancar dari compositor akan dihentikan.
Untuk mengurangi hal ini, Anda dapat meneruskan opsi passive: true
di pemroses peristiwa. Hal ini mengisyaratkan kepada browser bahwa Anda masih ingin memproses peristiwa di thread utama,
tetapi kompositor juga dapat melanjutkan dan menyusun frame baru.
document.body.addEventListener('touchstart', event => {
if (event.target === area) {
event.preventDefault()
}
}, {passive: true});
Memeriksa apakah peristiwa dapat dibatalkan
Bayangkan Anda memiliki kotak di halaman yang ingin Anda batasi arah scroll-nya hanya ke scroll horizontal.
Menggunakan opsi passive: true
dalam peristiwa pointer berarti scroll halaman dapat berjalan lancar, tetapi
scroll vertikal mungkin telah dimulai pada saat Anda ingin preventDefault
untuk membatasi
arah scroll. Anda dapat memeriksanya menggunakan metode event.cancelable
.
document.body.addEventListener('pointermove', event => {
if (event.cancelable) {
event.preventDefault(); // block the native scroll
/*
* do what you want the application to do here
*/
}
}, {passive: true});
Atau, Anda dapat menggunakan aturan CSS seperti touch-action
untuk sepenuhnya menghapus pengendali peristiwa.
#area {
touch-action: pan-x;
}
Menemukan target peristiwa
Saat thread kompositor mengirim peristiwa input ke thread utama, hal pertama yang harus dijalankan adalah hit test untuk menemukan target peristiwa. Pengujian hit menggunakan data catatan cat yang dihasilkan dalam proses rendering untuk mengetahui apa yang ada di bawah koordinat titik tempat peristiwa terjadi.
Meminimalkan pengiriman peristiwa ke thread utama
Di postingan sebelumnya, kita telah membahas cara layar standar memuat ulang layar 60 kali per detik dan cara kita harus mengikuti irama untuk animasi yang lancar. Untuk input, perangkat layar sentuh biasa mengirimkan peristiwa sentuh 60-120 kali per detik, dan mouse biasa mengirimkan peristiwa 100 kali per detik. Peristiwa input memiliki fidelitas yang lebih tinggi daripada kemampuan layar untuk memuat ulang.
Jika peristiwa berkelanjutan seperti touchmove
dikirim ke thread utama 120 kali per detik, hal ini
dapat memicu jumlah hit test dan eksekusi JavaScript yang berlebihan dibandingkan dengan seberapa lambat
layar dapat dimuat ulang.
Untuk meminimalkan panggilan yang berlebihan ke thread utama, Chrome menggabungkan peristiwa berkelanjutan (seperti
wheel
, mousewheel
, mousemove
, pointermove
, touchmove
) dan menunda pengiriman hingga
tepat sebelum requestAnimationFrame
berikutnya.
Setiap peristiwa terpisah seperti keydown
, keyup
, mouseup
, mousedown
, touchstart
, dan touchend
akan segera dikirim.
Menggunakan getCoalescedEvents
untuk mendapatkan peristiwa intra-frame
Untuk sebagian besar aplikasi web, peristiwa gabungan seharusnya cukup untuk memberikan pengalaman pengguna yang baik.
Namun, jika Anda mem-build hal-hal seperti aplikasi gambar dan menempatkan jalur berdasarkan
koordinat touchmove
, Anda mungkin kehilangan koordinat di antara untuk menggambar garis yang halus. Dalam hal ini,
Anda dapat menggunakan metode getCoalescedEvents
dalam peristiwa pointer untuk mendapatkan informasi tentang
peristiwa gabungan tersebut.
window.addEventListener('pointermove', event => {
const events = event.getCoalescedEvents();
for (let event of events) {
const x = event.pageX;
const y = event.pageY;
// draw a line using x and y coordinates.
}
});
Langkah berikutnya
Dalam seri ini, kita telah membahas cara kerja browser web. Jika Anda belum pernah memikirkan mengapa
DevTools merekomendasikan penambahan {passive: true}
pada pengendali peristiwa atau mengapa Anda mungkin menulis atribut async
di tag skrip, saya harap seri ini dapat menjelaskan mengapa browser memerlukan informasi
tersebut untuk memberikan pengalaman web yang lebih cepat dan lancar.
Menggunakan Lighthouse
Jika Anda ingin membuat kode yang baik untuk browser, tetapi tidak tahu harus memulai dari mana, Lighthouse adalah alat yang menjalankan audit situs apa pun dan memberi Anda laporan tentang apa yang dilakukan dengan benar dan apa yang perlu ditingkatkan. Membaca daftar audit juga memberi Anda gambaran tentang hal-hal yang penting bagi browser.
Pelajari cara mengukur performa
Penyesuaian performa dapat bervariasi untuk situs yang berbeda, jadi Anda harus mengukur performa situs dan memutuskan penyesuaian yang paling sesuai untuk situs Anda. Tim Chrome DevTools memiliki beberapa tutorial tentang cara mengukur performa situs Anda.
Menambahkan Kebijakan Fitur ke situs Anda
Jika Anda ingin melakukan langkah tambahan, Kebijakan Fitur adalah fitur platform web baru yang dapat menjadi penjaga bagi Anda saat mem-build project. Mengaktifkan
kebijakan fitur menjamin perilaku tertentu aplikasi Anda dan mencegah Anda melakukan kesalahan.
Misalnya, jika ingin memastikan aplikasi tidak akan pernah memblokir penguraian, Anda dapat menjalankan aplikasi pada
kebijakan skrip sinkron. Jika sync-script: 'none'
diaktifkan, JavaScript pemblokir parser akan
dicegah agar tidak dieksekusi. Hal ini mencegah kode Anda memblokir parser, dan browser tidak perlu khawatir untuk menjeda parser.
Rangkuman
Saat mulai membuat situs, saya hampir hanya peduli dengan cara menulis kode dan hal-hal yang akan membantu saya menjadi lebih produktif. Hal-hal tersebut penting, tetapi kita juga harus memikirkan cara browser mengambil kode yang kita tulis. Browser modern telah dan terus berinvestasi dalam cara untuk memberikan pengalaman web yang lebih baik bagi pengguna. Dengan memperlakukan browser dengan baik dengan mengatur kode, pengalaman pengguna Anda akan meningkat. Semoga Anda bergabung dengan saya dalam misi untuk bersikap baik kepada browser.
Terima kasih banyak kepada semua orang yang meninjau draf awal seri ini, termasuk (tetapi tidak terbatas pada): Alex Russell, Paul Irish, Meggin Kearney, Eric Bidelman, Mathias Bynens, Addy Osmani, Kinuko Yasuda, Nasko Oskov, dan Charlie Reis.
Apakah Anda menikmati seri ini? Jika ada pertanyaan atau saran untuk postingan mendatang, kami ingin mendengar pendapat Anda di bagian komentar di bawah atau @kosamari di Twitter.