Peristiwa input yang disejajarkan

Dave Tapuska
Dave Tapuska

TL;DR

  • Chrome 60 mengurangi jank dengan menurunkan frekuensi peristiwa, sehingga meningkatkan konsistensi pengaturan waktu frame.
  • Metode getCoalescedEvents(), yang diperkenalkan di Chrome 58, memberikan kekayaan informasi peristiwa yang sama seperti yang Anda miliki selama ini.

Memberikan pengalaman pengguna yang lancar sangat penting untuk web. Waktu antara menerima peristiwa input dan saat visual benar-benar diperbarui sangatlah penting dan umumnya melakukan lebih sedikit pekerjaan adalah hal yang penting. Selama beberapa rilis Chrome terakhir, kami telah mengurangi latensi input di seluruh perangkat ini.

Demi kelancaran dan performa, di Chrome 60, kami membuat perubahan yang menyebabkan peristiwa ini terjadi pada frekuensi yang lebih rendah sekaligus meningkatkan tingkat perincian informasi yang diberikan. Sama seperti saat Jelly Bean dirilis dan menghadirkan Choreographer yang menyelaraskan input di Android, kami menghadirkan input yang diselaraskan frame ke web di semua platform.

Namun, terkadang Anda memerlukan lebih banyak peristiwa. Jadi, di Chrome 58, kami menerapkan metode yang disebut getCoalescedEvents(), yang memungkinkan aplikasi Anda mengambil jalur lengkap pointer meskipun menerima lebih sedikit peristiwa.

Mari kita bahas frekuensi peristiwa terlebih dahulu.

Menurunkan frekuensi peristiwa

Mari kita pahami beberapa dasar: layar sentuh memberikan input pada 60-120 Hz dan mouse memberikan input biasanya pada 100 Hz (tetapi bisa hingga 2000 Hz). Namun, kecepatan refresh monitor biasanya 60 Hz. Jadi, apa artinya? Artinya, kami menerima input dengan kecepatan yang lebih tinggi daripada kecepatan update tampilan yang sebenarnya. Jadi, mari kita lihat linimasa performa dari devtools untuk aplikasi lukisan kanvas sederhana.

Pada gambar di bawah, dengan input yang diselaraskan requestAnimationFrame() dinonaktifkan, Anda dapat melihat beberapa blok pemrosesan per frame dengan waktu frame yang tidak konsisten. Blok kuning kecil menunjukkan pengujian hit untuk hal-hal seperti target peristiwa DOM, mengirim peristiwa, menjalankan JavaScript, memperbarui node yang diarahkan kursor, dan mungkin menghitung ulang tata letak dan gaya.

Linimasa performa yang menunjukkan pengaturan waktu frame yang tidak konsisten

Jadi, mengapa kita melakukan pekerjaan tambahan yang tidak menyebabkan pembaruan visual? Idealnya, kita tidak ingin melakukan pekerjaan apa pun yang pada akhirnya tidak menguntungkan pengguna. Mulai Chrome 60, pipeline input akan menunda pengiriman peristiwa berkelanjutan (wheel, mousewheel, touchmove, pointermove, mousemove) dan mengirimkannya tepat sebelum callback requestAnimationFrame() terjadi. Pada gambar di bawah (dengan fitur diaktifkan), Anda akan melihat waktu frame yang lebih konsisten dan waktu pemrosesan peristiwa yang lebih singkat.

Kami telah menjalankan eksperimen dengan mengaktifkan fitur ini di saluran Canary dan Dev, dan mendapati bahwa kami melakukan hit test 35% lebih sedikit, sehingga thread utama siap dijalankan lebih sering.

Catatan penting yang harus diketahui developer web adalah setiap peristiwa terpisah (seperti keydown, keyup, mouseup, mousedown, touchstart, touchend) yang terjadi akan langsung dikirim bersama dengan peristiwa yang tertunda, dengan mempertahankan urutan relatif. Dengan mengaktifkan fitur ini, banyak pekerjaan yang disederhanakan ke dalam alur loop peristiwa normal, yang memberikan interval input yang konsisten. Hal ini membuat peristiwa berkelanjutan selaras dengan peristiwa scroll dan resize yang telah disederhanakan ke dalam alur loop peristiwa di Chrome.

Linimasa performa yang menunjukkan pengaturan waktu frame yang relatif konsisten.

Kami mendapati bahwa sebagian besar aplikasi yang menggunakan peristiwa tersebut tidak memerlukan frekuensi yang lebih tinggi. Android telah menyelaraskan peristiwa selama beberapa tahun, jadi tidak ada yang baru, tetapi situs mungkin mengalami peristiwa yang kurang terperinci di platform desktop. Selalu ada masalah dengan thread utama yang tersendat yang menyebabkan gangguan pada kelancaran input, yang berarti Anda mungkin melihat lompatan posisi setiap kali aplikasi melakukan pekerjaan, sehingga tidak mungkin mengetahui cara pointer berpindah dari satu tempat ke tempat lain.

Metode getCoalescedEvents()

Seperti yang saya katakan, ada skenario langka saat aplikasi lebih memilih untuk mengetahui jalur lengkap pointer. Jadi, untuk memperbaiki kasus saat Anda melihat lonjakan besar dan frekuensi peristiwa yang berkurang, di Chrome 58, kami meluncurkan ekstensi untuk peristiwa pointer yang disebut getCoalescedEvents(). Dan di bawah ini adalah contoh bagaimana jank pada thread utama disembunyikan dari aplikasi jika Anda menggunakan API ini.

Membandingkan peristiwa standar dan gabungan.

Daripada menerima satu peristiwa, Anda dapat mengakses array peristiwa historis yang menyebabkan peristiwa tersebut. Android, iOS, dan Windows semuanya memiliki API yang sangat mirip di SDK native-nya dan kami mengekspos API yang serupa ke web.

Biasanya, aplikasi gambar mungkin telah menggambar titik dengan melihat offset pada peristiwa:

window.addEventListener("pointermove", function(event) {
    drawPoint(event.pageX, event.pageY);
});

Kode ini dapat dengan mudah diubah untuk menggunakan array peristiwa:

window.addEventListener("pointermove", function(event) {
    var events = 'getCoalescedEvents' in event ? event.getCoalescedEvents() : [event];
    for (let e of events) {
    drawPoint(e.pageX, e.pageY);
    }
});

Perhatikan bahwa tidak semua properti pada peristiwa gabungan diisi. Karena peristiwa yang digabungkan tidak benar-benar dikirim, tetapi hanya mengikuti perjalanan, peristiwa tersebut tidak diuji hit. Beberapa kolom seperti currentTarget, dan eventPhase akan memiliki nilai defaultnya. Memanggil metode terkait pengiriman seperti stopPropagation() atau preventDefault() tidak akan memengaruhi peristiwa induk.