Tampilan mendalam pada browser web modern (bagian 4)

Mariko Kosaka

Input akan dikirim ke Compositor

Ini adalah bagian terakhir dari 4 bagian blog yang membahas Chrome; menyelidiki bagaimana hal itu menangani kode kita untuk menampilkan sebuah situs web. Di postingan sebelumnya, kita melihat proses rendering dan mempelajari compositor. Dalam postingan ini, kita akan lihat bagaimana compositor memungkinkan interaksi yang mulus ketika masukan pengguna masuk.

Memasukkan peristiwa dari sudut pandang browser

Saat Anda mendengar "peristiwa input" Anda mungkin hanya berpikir mengetik di kotak teks atau klik {i>mouse<i}, tetapi dari sudut pandang browser, {i>input <i}berarti semua {i>gesture <i}dari pengguna. Scroll roda mouse adalah input dan sentuh atau mengarahkan mouse juga merupakan peristiwa input.

Saat {i>gesture <i}pengguna seperti menyentuh pada layar terjadi, proses {i>browser<i} adalah yang menerima {i>gesture <i}pertama kali. Namun, proses browser hanya menyadari di mana {i>gesture <i}itu terjadi karena konten di dalam tab ditangani oleh proses perender. Agar proses browser mengirimkan peristiwa jenis (seperti touchstart) dan koordinatnya untuk proses perender. Proses perender menangani secara tepat dengan mencari target peristiwa dan menjalankan pemroses peristiwa yang terpasang.

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

Compositor menerima peristiwa input

Gambar 2: Area pandang saat kursor diarahkan ke lapisan halaman

Di posting sebelumnya, kita melihat bagaimana compositor bisa menangani gulir secara lancar dengan mengomposisikan lapisan raster. Jika tidak ada pemroses peristiwa input yang dilampirkan ke halaman, thread Compositor dapat membuat {i>frame<i} komposit baru yang sepenuhnya independen dari utas utama. Tapi bagaimana jika beberapa peristiwa pendengar dikaitkan ke halaman? Bagaimana thread compositor mengetahui apakah peristiwa tersebut memerlukan untuk ditangani?

Memahami wilayah yang tidak dapat di-scroll cepat

Karena menjalankan JavaScript adalah tugas utas utama, saat sebuah halaman disusun, utas compositor menandai region halaman yang memiliki pengendali peristiwa yang dilampirkan sebagai "Wilayah Tidak Cepat yang Dapat Di-scroll". Menurut 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, maka utas compositor berguna untuk menyusun bingkai baru tanpa menunggu utas utama.

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

Berhati-hatilah saat Anda menulis pengendali peristiwa

Pola penanganan peristiwa yang umum dalam pengembangan web adalah delegasi peristiwa. Karena balon acara, Anda dapat melampirkan satu pengendali peristiwa di elemen teratas dan mendelegasikan tugas berdasarkan target peristiwa. Anda mungkin telah 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 peristiwa ini yang sangat menarik. Namun, jika Anda melihat kode ini dari sudut pandang browser , kini seluruh halaman ditandai sebagai wilayah yang tidak dapat di-scroll cepat. Ini berarti meskipun aplikasi tidak peduli dengan input dari bagian tertentu dari laman, thread compositor harus berkomunikasi dengan thread utama dan menunggunya setiap kali peristiwa input masuk. Dengan demikian, kemampuan scroll yang mulus dari compositor kalah.

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

Untuk mencegah hal ini terjadi, Anda dapat meneruskan opsi passive: true di acara Anda pemroses. Ini memberikan petunjuk ke browser bahwa Anda masih ingin memproses peristiwa di thread utama, tetapi compositor juga dapat melanjutkan dan menggabungkan {i>frame<i} 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 yang tetap di-scroll secara horizontal

Bayangkan Anda memiliki kotak di halaman yang Anda inginkan untuk membatasi arah scroll hanya untuk scroll horizontal.

Menggunakan opsi passive: true di peristiwa pointer Anda berarti scroll halaman dapat berjalan lancar, tetapi scroll vertikal mungkin sudah dimulai pada saat Anda ingin 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

hit test
Gambar 6: Thread utama melihat catatan cat yang menanyakan apa yang digambar pada titik x.y

Saat thread compositor mengirimkan peristiwa input ke thread utama, hal pertama yang akan dijalankan adalah hit untuk menemukan target peristiwa. Hit test menggunakan data kumpulan data paint yang dihasilkan dalam rendering untuk mencari tahu apa yang ada di bawah koordinat titik tempat peristiwa terjadi.

Meminimalkan pengiriman peristiwa ke thread utama

Dalam posting sebelumnya, kita membahas bagaimana tampilan biasa kita menyegarkan layar 60 kali per detik dan bagaimana kita harus mengikuti ritme untuk animasi yang mulus. Untuk input, layar sentuh biasa perangkat memberikan peristiwa sentuh 60-120 kali per detik, dan mouse biasa memberikan peristiwa 100 kali kedua. Peristiwa input memiliki fidelitas lebih tinggi daripada yang dapat dimuat ulang oleh layar.

Jika peristiwa berkelanjutan seperti touchmove dikirim ke thread utama 120 kali per detik, dapat memicu hit test dan eksekusi JavaScript secara 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 keterlambatan pengiriman hingga tepat sebelum requestAnimationFrame berikutnya.

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

Peristiwa terpisah apa pun seperti keydown, keyup, mouseup, mousedown, touchstart, dan touchend akan segera dikirim.

Gunakan getCoalescedEvents untuk mendapatkan peristiwa intra-frame

Untuk sebagian besar aplikasi web, peristiwa gabungan seharusnya cukup untuk memberikan pengalaman pengguna yang baik. Namun, jika Anda membangun hal-hal seperti menggambar aplikasi dan menempatkan jalur berdasarkan Koordinat touchmove, Anda bisa kehilangan di antara koordinat untuk menggambar garis yang mulus. Dalam kasus tersebut, Anda dapat menggunakan metode getCoalescedEvents dalam peristiwa pointer untuk mendapatkan informasi tentang peristiwa yang bersatu.

getCoalescedEvents
Gambar 9: Jalur gestur sentuh halus di sebelah kiri, yang digabungkan dengan 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, kami telah membahas cara kerja internal dari browser web. Jika Anda tidak pernah memikirkan mengapa DevTools merekomendasikan penambahan {passive: true} pada pengendali peristiwa atau alasan Anda menulis async di tag skrip Anda, saya harap rangkaian ini menjelaskan mengapa browser membutuhkannya. untuk memberikan pengalaman web yang lebih cepat dan lebih mulus.

Gunakan Lighthouse

Jika Anda ingin membuat kode Anda bagus untuk browser tetapi tidak tahu harus mulai dari mana, Lighthouse adalah alat yang menjalankan audit atas situs mana pun dan memberi Anda melaporkan apa yang sudah dilakukan dengan benar dan apa yang perlu diperbaiki. Membaca daftar audit juga memberikan gambaran hal-hal apa saja yang diperhatikan oleh browser.

Pelajari cara mengukur performa

Penyesuaian kinerja dapat bervariasi untuk situs yang berbeda, jadi penting bagi Anda untuk mengukur kinerja situs Anda dan menentukan apa yang paling sesuai untuk situs Anda. Tim Chrome DevTools memiliki beberapa tutorial tentang cara mengukur performa situs.

Menambahkan Kebijakan Fitur ke situs

Jika Anda ingin mengambil langkah tambahan, Kebijakan Fitur adalah platform web yang dapat menjadi pagar pembatas untuk Anda ketika Anda membangun proyek. Mengaktifkan kebijakan fitur menjamin perilaku tertentu aplikasi dan mencegah Anda melakukan kesalahan. Misalnya, jika Anda ingin memastikan aplikasi tidak akan pernah memblokir penguraian, Anda dapat menjalankan aplikasi di kebijakan skrip sinkron. Jika sync-script: 'none' diaktifkan, JavaScript yang memblokir parser akan dicegah agar tidak dijalankan. Hal ini mencegah kode Anda memblokir parser, dan tidak perlu khawatir menjeda parser.

Rangkuman

terima kasih

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

Terima kasih banyak kepada semua yang telah meninjau draf awal rangkaian ini, termasuk (tetapi tidak terbatas kepada): Alex Russell, Paul Irish, Meggin Kearney, Eric Bidelman, Mathias Bynens, Addy Osmani, Kinuko Yasuda, Nasko Oskov, dan Charlie Reis.

Apakah Anda menikmati serial ini? Jika Anda memiliki pertanyaan atau saran untuk postingan mendatang, Saya ingin mendengar pendapat Anda di bagian komentar di bawah atau @kosamari di Twitter.