JavaScript API baru yang dapat membantu Anda menghindari kompromi antara performa pemuatan dan responsivitas input.
Pemuatan dengan cepat itu sulit. Situs yang memanfaatkan JS untuk merender kontennya saat ini harus melakukan kompromi antara performa beban dan input responsivitas: melakukan semua pekerjaan yang diperlukan untuk menampilkan sekaligus (performa pemuatan yang lebih baik, respons input yang lebih buruk), atau membagi pekerjaan menjadi tugas-tugas yang lebih kecil agar tetap responsif terhadap input dan cat (performa pemuatan yang lebih buruk, input yang lebih baik tingkat respons).
Untuk menghilangkan keharusan melakukan {i>trade-off<i} ini, Facebook mengusulkan dan menerapkan
isInputPending()
API di Chromium untuk meningkatkan responsivitas tanpa
menghasilkan sesuatu. Berdasarkan masukan uji coba origin, kami telah melakukan sejumlah pembaruan pada
API, dan dengan senang hati mengumumkan bahwa API tersebut kini dikirimkan secara default di Chromium
87!
Kompatibilitas browser
isInputPending()
dikirim di browser berbasis Chromium mulai versi 87.
Tidak ada browser lain yang menunjukkan intent untuk mengirimkan API.
Latar belakang
Sebagian besar pekerjaan di ekosistem JS saat ini dilakukan di satu thread: thread utama. Hal ini memberikan model eksekusi yang tangguh bagi developer, tetapi pengalaman pengguna (khususnya responsivitas) dapat menurun secara drastis jika skrip dieksekusi untuk waktu yang lama baik. Jika halaman melakukan banyak pekerjaan saat peristiwa input diaktifkan, misalnya, halaman tidak akan menangani peristiwa input klik hingga peristiwa tersebut bekerja selesai.
Praktik terbaik saat ini adalah mengatasi masalah ini dengan melanggar JavaScript menjadi blok yang lebih kecil. Selagi halaman dimuat, halaman dapat menjalankan sedikit JavaScript, lalu menghasilkan dan meneruskan kontrol kembali ke browser. Tujuan {i>browser <i}kemudian dapat memeriksa antrean kejadian inputnya dan melihat apakah ada sesuatu yang perlu diberitahukan kepada halaman. Kemudian browser dapat kembali menjalankan Blok JavaScript saat ditambahkan. Hal ini membantu, tetapi dapat menyebabkan masalah lain.
Setiap kali laman mengembalikan kontrol ke {i>browser<i}, dibutuhkan beberapa waktu untuk browser untuk memeriksa antrean kejadian inputnya, memproses peristiwa, dan mengambil Pemblokiran JavaScript. Saat browser merespons kejadian lebih cepat, keseluruhan waktu pemuatan halaman akan melambat. Jika kita terlalu sering menyerah, halaman memuat terlalu lambat. Jika kami lebih jarang memberikan hasil, browser akan memerlukan waktu lebih lama untuk menanggapi kejadian pengguna, dan orang-orang menjadi frustrasi. Tidak seru.
Di Facebook, kami ingin melihat seperti apa
segala sesuatu yang akan terjadi jika kami memiliki
pendekatan baru untuk pemuatan yang akan menghilangkan {i>trade-off<i} yang menjengkelkan ini. Rab
menghubungi teman-teman kami di Chrome tentang hal ini, dan mendapatkan proposal
untuk isInputPending()
. isInputPending()
API adalah yang pertama menggunakan konsep
menginterupsi input pengguna di web, dan
memungkinkan JavaScript
dapat memeriksa input tanpa bergantung pada browser.
Karena ada minat terhadap API tersebut, kami berpartner dengan kolega kami di Chrome untuk menerapkan dan mengirimkan fitur ini di Chromium. Dengan bantuan dari Chrome engineer, kami menerapkan patch pada uji coba origin (yang merupakan cara Chrome untuk menguji perubahan dan mendapatkan masukan dari developer sebelum merilis API sepenuhnya).
Sekarang kami telah menerima masukan dari uji coba origin dan dari anggota lain dalam W3C Web Performance Working Group dan menerapkan perubahan pada API.
Contoh: penjadwal yang lebih produktif
Misalkan Anda memiliki banyak tugas pemblokiran tampilan yang harus dilakukan untuk memuat
misalnya menghasilkan markup dari komponen, memfaktorkan bilangan prima, atau
hanya menampilkan indikator lingkaran berputar pemuatan yang keren. Masing-masing ini dipecah menjadi
item pekerjaan. Dengan menggunakan pola penjadwal, mari kita
sketsa bagaimana kita mungkin memproses
pekerjaan kita dalam fungsi processWorkQueue()
fiktif:
const DEADLINE = performance.now() + QUANTUM;
while (workQueue.length > 0) {
if (performance.now() >= DEADLINE) {
// Yield the event loop if we're out of time.
setTimeout(processWorkQueue);
return;
}
let job = workQueue.shift();
job.execute();
}
Dengan memanggil processWorkQueue()
nanti dalam macrotask baru melalui setTimeout()
, kita
memberi browser kemampuan untuk tetap agak responsif terhadap input (dapat
menjalankan pengendali peristiwa sebelum pekerjaan dilanjutkan) sambil tetap mengelola untuk menjalankan
tanpa gangguan. Meskipun demikian, kami mungkin mendapatkan
jadwal waktu yang lama oleh pekerjaan lain
yang menginginkan kontrol loop peristiwa, atau mendapatkan hingga QUANTUM
milidetik tambahan
latensi peristiwa.
Tidak apa-apa, tetapi bisakah kita melakukan lebih baik? Tentu saja!
const DEADLINE = performance.now() + QUANTUM;
while (workQueue.length > 0) {
if (navigator.scheduling.isInputPending() || performance.now() >= DEADLINE) {
// Yield if we have to handle an input event, or we're out of time.
setTimeout(processWorkQueue);
return;
}
let job = workQueue.shift();
job.execute();
}
Dengan memperkenalkan panggilan kepada navigator.scheduling.isInputPending()
, kita dapat
merespons input lebih cepat sambil tetap memastikan bahwa fungsi pemblokir tampilan kami
tanpa gangguan. Jika kami tidak tertarik untuk menangani apa pun
selain input (mis. mengecat) sampai pekerjaan selesai, kita dapat dengan mudah meningkatkan
panjang QUANTUM
juga.
Secara default, "berkelanjutan" peristiwa tidak ditampilkan dari isInputPending()
. Ini
termasuk mousemove
, pointermove
, dan lainnya. Jika Anda tertarik untuk mengumpulkan
ini juga, tidak masalah. Dengan menyediakan objek ke isInputPending()
dengan
includeContinuous
disetel ke true
, kita siap memulai:
const DEADLINE = performance.now() + QUANTUM;
const options = { includeContinuous: true };
while (workQueue.length > 0) {
if (navigator.scheduling.isInputPending(options) || performance.now() >= DEADLINE) {
// Yield if we have to handle an input event (any of them!), or we're out of time.
setTimeout(processWorkQueue);
return;
}
let job = workQueue.shift();
job.execute();
}
Selesai. Framework seperti React membangun dukungan isInputPending()
ke dalam
library penjadwalan inti menggunakan logika serupa. Semoga, ini akan mengarahkan
developer yang menggunakan framework ini agar dapat memperoleh manfaat dari isInputPending()
di balik layar tanpa
penulisan ulang yang signifikan.
Hasil tidak selalu buruk
Perlu dicatat bahwa menghasilkan lebih sedikit bukan solusi yang tepat untuk setiap penggunaan ini masalahnya atau bukan. Ada banyak alasan untuk mengembalikan kontrol ke {i>browser<i} selain untuk memproses peristiwa input, seperti melakukan rendering dan mengeksekusi skrip lain di pada halaman.
Ada kasus saat browser tidak dapat mengatribusikan dengan benar
peristiwa input. Secara khusus, menyetel klip dan mask yang kompleks untuk lintas origin
iframe mungkin melaporkan negatif palsu (yaitu isInputPending()
mungkin ditampilkan secara tidak terduga
false saat menargetkan frame ini). Pastikan bahwa Anda menghasilkan
cukup sering jika
situs Anda membutuhkan interaksi dengan subframe bergaya.
Perhatikan juga halaman lain yang berbagi loop peristiwa. Di platform seperti
seperti Chrome untuk Android, cukup umum bagi beberapa origin untuk membagikan suatu peristiwa
. isInputPending()
tidak akan pernah menampilkan true
jika input dikirim ke
kerangka lintas asal, dan karenanya laman di latar belakang dapat mengganggu
tingkat respons laman latar depan. Anda mungkin ingin mengurangi, menunda, atau menyerah
lebih sering saat melakukan pekerjaan di latar belakang menggunakan Page Visibility API.
Sebaiknya gunakan isInputPending()
dengan bijak. Jika tidak ada
tugas yang memblokir pengguna harus dilakukan, lalu berbaik hatilah kepada orang lain pada loop peristiwa dengan
menghasilkan lebih sering. Tugas yang berjalan lama bisa berbahaya.
Masukan
- Berikan masukan tentang spesifikasi di is-input-pending.
- Hubungi @acomminos (salah satu penulis spesifikasi) di Twitter.
Kesimpulan
Kami senang isInputPending()
diluncurkan, dan para developer dapat
untuk mulai menggunakannya sekarang. API ini adalah pertama kalinya Facebook membuat
API web baru dan membawanya dari inkubasi ide
ke proposal standar hingga benar-benar
pengiriman di browser. Kami ingin berterima kasih kepada semua orang yang telah membantu kami mencapai
dan berikan sapaan khusus kepada semua orang di Chrome yang telah membantu kami menyempurnakan
ide ini dan kirimkan!
Foto utama oleh will H McMahan di Buka pembuka.