Debounce vs Throttle: Atasi Event Beruntun di JavaScript
Pahami beda debounce dan throttle, kapan memakainya untuk pencarian, scroll, dan resize, serta cara beberapa baris JavaScript menjaga UI tetap responsif.

Ketik satu kata di kolom pencarian, dan kodemu bisa bereaksi sepuluh kali. Gulir sebuah halaman, dan listener scroll bisa terpicu puluhan kali per detik. Jika setiap event menjalankan proses berat atau permintaan ke server, antarmuka mulai tersendat. Debounce dan throttle adalah dua teknik kecil untuk mengatasinya, dan setiap developer frontend perlu tahu bedanya.
Masalahnya: event yang terpicu terlalu sering
Browser melaporkan aktivitas pengguna dengan sangat rinci. Ketikan, gerakan mouse, scroll, dan perubahan ukuran jendela masing-masing bisa menghasilkan rentetan event. Biasanya kamu tidak perlu merespons semuanya. Yang dibutuhkan hanyalah hasil pada saat yang tepat.
Pekerjaan berlebihan di setiap event akan memblokir main thread. Ini memperburuk Interaction to Next Paint (INP), metrik responsivitas dalam Core Web Vitals dari Google, yang kami jelaskan dengan bahasa sederhana di artikel tentang Core Web Vitals.
Apa itu debounce?
Debounce menunggu sampai rentetan event berhenti. Setiap event baru mengulang timer, dan fungsi baru dijalankan setelah pengguna diam selama jeda tertentu.
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
const onSearch = debounce((q) => fetchResults(q), 300);Jika seseorang mengetik "desain" dengan cepat, hanya satu permintaan yang dikirim, sekitar 300 ms setelah tombol terakhir ditekan.
Apa itu throttle?
Throttle menetapkan batas kecepatan. Fungsi dijalankan paling banyak satu kali per interval, berapa pun jumlah event yang masuk di antaranya.
function throttle(fn, interval) {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last >= interval) {
last = now;
fn(...args);
}
};
}
window.addEventListener('scroll', throttle(updateProgressBar, 100));Selama scroll panjang, progress bar diperbarui secara stabil setiap 100 ms, bukan pada setiap event.
Panggilan leading dan trailing
Kedua teknik bisa dijalankan di awal rentetan (leading), di akhir (trailing), atau keduanya. Contoh throttle sederhana di atas hanya leading, sehingga bisa melewatkan event paling akhir. Library sudah menangani kasus seperti ini: debounce dan throttle dari Lodash menyediakan opsi leading, trailing, dan maxWait.
Mana yang sebaiknya dipakai?
Aturan sederhananya: gunakan debounce jika kamu hanya peduli nilai akhir, dan throttle jika butuh pembaruan rutin selama aksi berlangsung.
Saran pencarian dan validasi formulir: debounce. Kamu butuh input yang sudah selesai, bukan setiap huruf.
Simpan draf otomatis: debounce, agar penyimpanan terjadi saat penulis berhenti sejenak.
Posisi scroll, infinite scroll, dan analitik: throttle, agar umpan balik tetap mulus selama scroll.
Layout saat resize jendela: debounce untuk perhitungan ulang yang berat, throttle jika layout harus mengikuti tarikan secara langsung.
Mencegah klik tombol berulang: debounce atau throttle dengan mode leading menghentikan pengiriman ganda.
Panduan debounce dan throttle dari CSS-Tricks punya demo interaktif yang membuat perbedaannya mudah dilihat.
Tips dan kesalahan umum
Buat fungsi pembungkusnya sekali saja. Memanggil
debounce()di dalam render atau handler event akan membuat timer baru setiap kali, sehingga tidak ada yang benar-benar di-debounce. Di React, jaga agar tetap stabil denganuseMemoatauuseRef.Gunakan requestAnimationFrame untuk pembaruan visual. Untuk animasi yang mengikuti scroll, requestAnimationFrame menyelaraskan pekerjaan dengan refresh layar, dan sering kali lebih mulus daripada timer tetap.
Batalkan permintaan yang sudah usang. Debounce mengurangi jumlah permintaan, tetapi respons lama tetap bisa datang setelah respons yang lebih baru. Padukan dengan AbortController untuk membuang fetch yang sudah tidak relevan.
Tentukan jeda berdasarkan rasa. Sekitar 200 sampai 400 ms cocok untuk mengetik. Terlalu lama membuat UI terasa lambat, terlalu singkat hampir tidak ada manfaatnya.
Bersihkan timer. Hapus timer yang masih tertunda saat komponen di-unmount agar callback tidak berjalan di halaman yang sudah tidak ada.
Debounce menunggu hening. Throttle menjaga ketukan yang stabil.
Jelajahi lebih lanjut
Kebiasaan performa kecil seperti ini membuat antarmuka terasa instan. Jika kamu juga sedang merapikan kode, baca panduan kami tentang menjauhkan API key dari kode, atau lihat software yang kami bangun di Ryuartistry.