Menguasai Main Thread Scheduling API: Membangun UI Responsif dengan isInputPending dan scheduler.yield
1. Pendahuluan
Pernahkah Anda mengalami aplikasi web yang terasa “macet” atau tidak responsif saat Anda mencoba berinteraksi dengannya? Mungkin Anda mengklik tombol, tetapi tidak ada yang terjadi selama beberapa detik, atau animasi tiba-tiba berhenti. Ini adalah tanda bahwa Main Thread browser Anda sedang terblokir. Main Thread adalah jantung dari setiap aplikasi web, bertanggung jawab untuk semua hal penting: rendering UI, menjalankan JavaScript, menangani event pengguna, dan banyak lagi. Ketika Main Thread sibuk dengan tugas yang berat, ia tidak bisa merespons interaksi pengguna, menyebabkan pengalaman yang buruk.
Untungnya, web terus berevolusi, dan browser modern kini menyediakan API canggih untuk membantu developer mengelola Main Thread dengan lebih baik. Dua API yang relatif baru dan sangat powerful adalah isInputPending() dan scheduler.yield(). Kedua API ini memungkinkan Anda untuk menerapkan cooperative scheduling di Main Thread, memberikan kontrol lebih granular atas kapan dan bagaimana tugas berat dieksekusi, sekaligus memastikan interaksi pengguna selalu diprioritaskan.
Artikel ini akan membawa Anda menyelami kedua API ini: bagaimana cara kerjanya, kapan menggunakannya, dan bagaimana mengombinasikannya untuk membangun aplikasi web yang super responsif dan menyenangkan bagi pengguna Anda.
2. Memahami Main Thread Blocking: Musuh Utama Responsivitas
Bayangkan Main Thread sebagai seorang chef di dapur restoran yang sangat sibuk. Chef ini harus memasak (menjalankan JavaScript), melayani pelanggan (merespons event pengguna), dan menjaga kebersihan dapur (merender UI). Jika chef terlalu lama sibuk memasak hidangan yang sangat kompleks, ia tidak akan bisa melayani pelanggan baru atau membersihkan meja. Pelanggan akan menunggu, frustrasi, dan mungkin pergi.
Di dunia web, “memasak hidangan kompleks” bisa berarti:
- Pemrosesan data yang intensif: Melakukan kalkulasi kompleks pada array besar, memfilter daftar ribuan item.
- Rendering UI yang berat: Membangun atau memperbarui DOM yang sangat besar, menjalankan animasi yang kompleks.
- Memuat atau memproses aset besar: Misalnya, memproses gambar atau video di sisi klien.
Ketika tugas-tugas ini berjalan terlalu lama (lebih dari 50 milidetik, bahkan lebih baik jika di bawah 16ms untuk 60fps), Main Thread akan “terblokir”. Ini berarti browser tidak bisa:
- Merespons klik, ketikan, atau scroll dari pengguna.
- Memperbarui UI, menyebabkan animasi tersendat atau UI terasa beku.
- Menjalankan script lain yang seharusnya interaktif.
❌ Dampaknya: Pengalaman pengguna yang buruk, aplikasi terasa lambat, dan bahkan dapat memengaruhi Core Web Vitals seperti Interaction to Next Paint (INP).
3. Solusi Tradisional vs. Kebutuhan Baru
Selama ini, developer menggunakan beberapa teknik untuk memecah tugas berat agar Main Thread tidak terblokir:
-
setTimeout(..., 0): Memecah tugas menjadi potongan-potongan kecil dan menjadwalkannya di akhir antrean event loop. Ini memberikan waktu bagi browser untuk merespons event lain di antara potongan tugas.function processLargeArray(arr) { let i = 0; function processChunk() { const start = Date.now(); while (i < arr.length && (Date.now() - start < 10)) { // Proses selama 10ms // Lakukan pemrosesan pada arr[i] console.log(`Processing item ${arr[i]}`); i++; } if (i < arr.length) { setTimeout(processChunk, 0); // Jadwalkan chunk berikutnya } else { console.log('Processing complete!'); } } setTimeout(processChunk, 0); }⚠️ Keterbatasan:
setTimeouttidak tahu apakah ada input pengguna yang tertunda. Ia hanya menjadwalkan ulang tugas secara buta. Prioritasnya juga rendah, bisa saja ada tugas lain yang lebih penting yang menunggu. -
requestIdleCallback(): Menjadwalkan tugas untuk dijalankan saat browser “idle” (tidak ada pekerjaan penting lainnya). ⚠️ Keterbatasan: Tidak ada jaminan kapan atau apakah callback akan dipanggil. Tidak cocok untuk tugas yang harus selesai dalam waktu tertentu atau yang membutuhkan responsivitas cepat terhadap input. -
Web Workers: Memindahkan tugas komputasi berat ke thread terpisah, sehingga Main Thread tetap bebas. ✅ Kelebihan: Solusi terbaik untuk komputasi yang sangat berat. ⚠️ Keterbatasan: Tidak bisa mengakses DOM secara langsung, memerlukan komunikasi antar thread yang bisa menambah overhead untuk tugas-tugas yang lebih kecil dan interaktif.
-
scheduler.postTask(): API yang lebih baru untuk menjadwalkan tugas dengan prioritas tertentu (background, user-blocking, user-visible). ✅ Kelebihan: Memberikan kontrol prioritas yang lebih baik. ⚠️ **