Tampilan mendalam pada browser web modern (bagian 4)

Mariko Kosaka

Input masuk ke Compositor

Ini adalah seri blog terakhir dari 4 bagian yang membahas bagian dalam Chrome; yang menyelidiki cara penanganan kode kami untuk menampilkan situs. Pada postingan sebelumnya, kita melihat proses rendering dan mempelajari compositor. Dalam postingan ini, kita akan melihat bagaimana compositor memungkinkan interaksi yang lancar saat input pengguna masuk.

Memasukkan peristiwa 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 sentuhan atau pengarahan mouse juga merupakan peristiwa input.

Saat gestur pengguna seperti sentuhan pada layar terjadi, proses browser adalah yang pertama kali menerima gestur. Namun, proses browser hanya mengetahui tempat terjadinya gestur 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 secara tepat dengan menemukan target peristiwa dan menjalankan pemroses peristiwa yang disertakan.

peristiwa input
Gambar 1: Peristiwa input yang dirutekan melalui proses browser ke proses perender

Compositor menerima peristiwa input

Gambar 2: Area pandang yang mengarahkan kursor ke lapisan halaman

Dalam postingan sebelumnya, kita melihat bagaimana compositor dapat menangani scroll dengan lancar dengan mengomposisikan lapisan yang diraster. Jika tidak ada pemroses peristiwa input yang dikaitkan ke halaman, thread Compositor dapat membuat frame komposit baru yang sepenuhnya independen dari thread utama. Tetapi bagaimana jika beberapa pemroses peristiwa ditambahkan ke halaman? Bagaimana thread compositor mengetahui apakah peristiwa perlu ditangani?

Memahami region yang tidak dapat di-scroll

Karena menjalankan JavaScript adalah tugas thread utama, saat halaman digabungkan, thread compositor akan menandai wilayah halaman yang pengendali peristiwanya dikaitkan sebagai "Wilayah Non-Fast Scrollable". Dengan memiliki informasi ini, thread compositor dapat memastikan untuk mengirim peristiwa input ke thread utama jika peristiwa terjadi di region tersebut. Jika peristiwa input berasal dari luar region ini, thread compositor akan melanjutkan komposisi frame baru tanpa menunggu thread utama.

wilayah yang tidak dapat di-scroll dan terbatas
Gambar 3: Diagram input yang dijelaskan ke wilayah yang tidak dapat di-scroll dengan cepat

Berhati-hatilah saat Anda menulis pengendali peristiwa

Pola penanganan peristiwa yang umum dalam pengembangan web adalah delegasi peristiwa. Karena peristiwa berupa balon, Anda dapat memasang satu pengendali peristiwa di elemen paling atas dan mendelegasikan tugas berdasarkan target peristiwa. Anda mungkin pernah melihat atau menulis kode seperti di bawah ini.

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, seluruh halaman akan ditandai sebagai region yang tidak dapat di-scroll dengan cepat. Artinya, meskipun aplikasi Anda tidak memedulikan input dari bagian tertentu pada halaman, thread compositor harus berkomunikasi dengan thread utama dan menunggunya setiap kali peristiwa input masuk. Dengan demikian, kemampuan scroll mulus pada compositor akan terganggu.

wilayah halaman penuh yang tidak dapat di-scroll
Gambar 4: Diagram input yang dijelaskan ke wilayah tidak cepat yang dapat di-scroll yang mencakup seluruh halaman

Untuk mengurangi hal ini, Anda dapat meneruskan opsi passive: true di pemroses peristiwa. Ini memberikan petunjuk bagi browser bahwa Anda masih ingin memproses peristiwa di thread utama, tetapi compositor juga dapat melanjutkan dan menggabungkan frame baru.

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});

Memeriksa apakah acara dapat dibatalkan

scroll halaman
Gambar 5: Halaman web dengan bagian halaman tetap ke scroll horizontal

Bayangkan Anda memiliki kotak di halaman yang ingin Anda batasi arah scrollnya hanya untuk 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 melakukan preventDefault untuk membatasi arah scroll. Anda dapat memeriksanya dengan 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 menghilangkan pengendali peristiwa.

#area {
  touch-action: pan-x;
}

Menemukan target peristiwa

tes cepat
Gambar 6: Thread utama yang melihat catatan paint yang menanyakan apa yang digambar pada titik x.y

Saat thread compositor mengirim peristiwa input ke thread utama, hal pertama yang harus dijalankan adalah hit test untuk menemukan target peristiwa. Hit test menggunakan data rekaman paint yang dihasilkan dalam proses rendering untuk mengetahui apa yang ada di bawah koordinat titik saat peristiwa terjadi.

Meminimalkan pengiriman peristiwa ke thread utama

Dalam postingan sebelumnya, kita membahas cara layar standar kami memuat ulang 60 kali per detik dan bagaimana kita harus mengikuti ritme untuk animasi yang lancar. Untuk input, perangkat layar sentuh biasa memberikan peristiwa sentuh 60-120 kali per detik, dan mouse biasa mengirimkan peristiwa 100 kali detik. Peristiwa input memiliki fidelitas yang lebih tinggi daripada yang dapat dimuat ulang oleh layar.

Jika peristiwa berkelanjutan seperti touchmove dikirim ke thread utama 120 kali per detik, peristiwa tersebut mungkin memicu jumlah hit test dan eksekusi JavaScript yang berlebihan dibandingkan dengan seberapa lambat layar dapat dimuat ulang.

peristiwa yang tidak difilter
Gambar 7: Peristiwa membanjiri linimasa frame yang menyebabkan jank halaman

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.

peristiwa gabungan
Gambar 8: Linimasa yang sama seperti sebelumnya, tetapi peristiwa digabungkan dan tertunda

Semua 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 harus cukup untuk memberikan pengalaman pengguna yang baik. Namun, jika Anda membangun hal-hal seperti menggambar aplikasi dan menempatkan jalur berdasarkan koordinat touchmove, Anda dapat kehilangan koordinat di antara koordinat untuk menggambar garis halus. Dalam hal ini, Anda dapat menggunakan metode getCoalescedEvents dalam peristiwa pointer untuk mendapatkan informasi tentang peristiwa gabungan tersebut.

getCoalescedEvents
Gambar 9: Jalur gestur sentuh halus di sebelah kiri, menggabungkan jalur terbatas di sebelah kanan
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 internal {i>browser<i} web. Jika Anda belum pernah memikirkan alasan DevTools merekomendasikan penambahan {passive: true} di pengendali peristiwa atau alasan Anda menulis atribut async di tag skrip, semoga rangkaian ini menjelaskan alasan browser memerlukan informasi tersebut untuk memberikan pengalaman web yang lebih cepat dan lancar.

Menggunakan Lighthouse

Jika Anda ingin menyesuaikan kode dengan browser, tetapi tidak tahu harus memulai dari mana, Lighthouse adalah alat yang menjalankan audit pada situs mana pun dan memberi Anda laporan tentang apa yang telah dilakukan dengan benar dan apa yang perlu ditingkatkan. Dengan membaca daftar audit, Anda juga dapat mengetahui hal-hal yang menjadi perhatian browser.

Pelajari cara mengukur performa

Penyesuaian performa dapat bervariasi untuk berbagai situs, jadi penting bagi Anda untuk mengukur performa situs dan memutuskan hal yang paling cocok untuk situs Anda. Tim Chrome DevTools memiliki beberapa tutorial tentang cara mengukur performa situs.

Tambahkan Kebijakan Fitur ke situs Anda

Jika Anda ingin mengambil langkah tambahan, Kebijakan Fitur adalah fitur platform web baru yang dapat menjadi pagar pembatas saat Anda membangun project. Mengaktifkan kebijakan fitur akan 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. Saat sync-script: 'none' diaktifkan, JavaScript yang memblokir parser akan dicegah eksekusinya. Tindakan ini akan mencegah kode Anda memblokir parser, dan browser tidak perlu menjeda parser.

Penutup

terima kasih

Ketika saya mulai membuat {i>website<i}, saya hampir hanya peduli tentang bagaimana saya akan menulis kode dan apa yang akan membantu saya menjadi lebih produktif. Hal-hal itu penting, tetapi kita juga harus memikirkan bagaimana browser mengambil kode yang kita tulis. Browser modern telah dan terus berinvestasi dalam cara-cara untuk memberikan pengalaman web yang lebih baik bagi pengguna. Bersikap baik terhadap browser dengan mengatur kode pada akhirnya akan meningkatkan pengalaman pengguna Anda. Semoga Anda bergabung dengan saya dalam upaya untuk bersikap baik pada browser!

Terima kasih banyak kepada semua yang telah meninjau draf awal seri ini, termasuk (tetapi tidak terbatas pada): Alex Russell, Paul Irish, Meggin Kearney, Eric Bidelman, Mathias Bynens, Addy Osmani, Kinuko Yasuda,

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.