Input terasa lag karena event input memanggil fungsi berat setiap karakter diketik. Perbaikan tercepat adalah debounce: tunda eksekusi sampai pengguna berhenti mengetik sekitar 300 ms, lalu jalankan sekali saja. Pola ini memangkas puluhan request fetch menjadi satu dan membuat kolom search kembali responsif.
Penyebab Input Event Meledak saat Mengetik
Browser menembakkan event input dan keyup untuk tiap huruf, tempel teks, sampai hapus karakter. Tanpa jeda, semua pemicu itu langsung menjalankan logika di dalamnya.
- Fungsi pencarian terpanggil tiap karakter sehingga request fetch menumpuk dan saling mendahului.
- Manipulasi DOM berat seperti render daftar hasil ikut berjalan berulang dan memblokir proses ketik.
- Tidak ada pembatalan request lama, cache hasil, atau pengecekan input kosong sebelum fetch.
Bedakan Debounce vs Throttle untuk Kasus Input
Debounce menunggu aktivitas berhenti dulu, baru menjalankan fungsi sekali. Pola ini cocok untuk kolom search, autocomplete, dan validasi form karena pengguna biasanya mengetik beberapa karakter berurutan.
Throttle membatasi fungsi berjalan maksimal sekali per interval, misalnya tiap 200 ms. Pola ini cocok untuk scroll, resize, dan mousemove yang harus memberi respons berkala selama aktivitas berlangsung.
| Kondisi | Penyebab | Solusi |
|---|---|---|
| Search memicu fetch tiap huruf | Listener input tanpa jeda | Debounce 250 sampai 400 ms |
| Daftar autocomplete berkedip | Respons lama datang belakangan | AbortController untuk batalkan request |
| Scroll berat dan patah | Handler berjalan terlalu sering | Throttle per interval |
Cara Memperbaiki dengan Debounce di Browser
Ikuti urutan ini di JavaScript browser dengan addEventListener dan clearTimeout.
- Pasang listener
inputpada elemen search dan bacae.target.value. - Simpan ID timer di variabel luar, lalu panggil
clearTimeoutsetiap event baru masuk. - Buat timer baru dengan
setTimeoutsekitar 300 ms untuk menunda pencarian. - Jalankan fetch hanya setelah timer selesai dan input tidak kosong.
const input = document.querySelector("#search");
let timer;
function debounceSearch(value) {
if (!value.trim()) return;
fetch(`/api/search?q=${encodeURIComponent(value)}`)
.then((res) => {
if (!res.ok) throw new Error("Search gagal: " + res.status);
return res.json();
})
.then(renderHasil);
}
input.addEventListener("input", (e) => {
clearTimeout(timer);
timer = setTimeout(() => debounceSearch(e.target.value), 300);
});
Kode di atas menunda debounceSearch sampai 300 ms tanpa ketikan baru. Untuk race condition, simpan objek AbortController dan panggil abort() sebelum membuat request berikutnya.
Cara Mencegah Kambuh dan Memory Leak
- Hapus listener dengan
removeEventListenerdan panggilclearTimeoutsaat elemen input dilepas dari DOM. - Simpan hasil pencarian terakhir dalam object cache agar kata kunci sama tidak memicu fetch ulang.
- Hentikan fetch untuk input kosong dan tampilkan status awal saja.
- Pindahkan validasi berat, regex panjang, dan format ulang daftar keluar dari handler
input.
FAQ
Kapan pakai debounce dibanding throttle untuk input?
Pakai debounce untuk search dan validasi yang cukup berjalan sekali setelah berhenti mengetik.
Berapa delay debounce yang aman untuk search?
Gunakan 250 sampai 400 ms, dengan 300 ms sebagai titik awal yang seimbang.
Kenapa hasil search lama masih muncul duluan?
Request lama selesai belakangan dan menimpa hasil baru, batalkan dengan AbortController.