Debounce & Throttle — Performance

Debounce & Throttle Event seperti scroll, resize, dan input bisa fire ratusan kali per detik. Tanpa kontrol, handler yang berat akan membuat halaman tidak…

Event seperti input, scroll, dan resize bisa terjadi puluhan kali per detik. Kalau tiap event langsung menjalankan kerja berat, misalnya kirim request ke server, halamannya jadi berat dan server-nya kebanjiran. Debounce dan throttle adalah dua cara membatasi seberapa sering sebuah function benar-benar jalan. Bayangin pintu lift: pintunya baru menutup setelah 3 detik gak ada orang masuk, dan tiap ada yang masuk hitungannya mulai lagi. Itu debounce. Sekarang bayangin dispenser yang cuma mengeluarkan satu gelas tiap 3 detik, mau tombolnya kamu tekan berapa kali pun. Itu throttle.

🧪 Tebakan cepat: kolom pencarian memakai debounce 300 ms. Kamu mengetik "sate" dengan jeda 100 ms antar huruf, lalu berhenti. Berapa request yang terkirim: 4, 1, atau 0? Jawabannya ada di bagian "Debounce: tunggu sampai berhenti".

Debounce: tunggu sampai berhenti

Debounce menunda function sampai event-nya berhenti selama delay ms. Tiap panggilan baru membatalkan jadwal yang lama dan memasang jadwal baru.

Waktu Kamu mengetik Yang terjadi
0 ms s jadwal dipasang: jalan di ms ke-300
100 ms sa jadwal lama dibatalkan, jadwal baru: ms ke-400
200 ms sat dibatalkan lagi, jadwal baru: ms ke-500
300 ms sate dibatalkan lagi, jadwal baru: ms ke-600
600 ms (diam) cari("sate") jalan, request terkirim

Empat ketikan, 1 request, dengan kata terakhirnya. Itu jawaban tebakannya.

function debounce(fn, delay) {
  let timer = null;

  return function (...args) {
    clearTimeout(timer); // batalkan jadwal sebelumnya
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

const cari = debounce((kata) => {
  console.log("fetch /api/search?q=" + kata);
}, 300);

cari("s");
cari("sa");
cari("sat");
cari("sate");
// 300 ms setelah panggilan terakhir, sekali saja:
// fetch /api/search?q=sate

Tiga hal yang harus benar: sebelum delay lewat, fn belum jalan sama sekali; tiga panggilan beruntun cuma menghasilkan satu kali jalan; dan setelah jalan, pembungkusnya bisa dipakai lagi untuk gelombang berikutnya.

Throttle: paling banyak sekali per interval

Throttle menjalankan function paling banyak sekali tiap interval ms, selama event-nya terus datang. Event di antaranya dibuang.

function throttle(fn, interval) {
  let terakhir = 0;

  return function (...args) {
    const sekarang = Date.now();
    if (sekarang - terakhir >= interval) {
      terakhir = sekarang;
      fn.apply(this, args);
    }
  };
}

window.addEventListener("scroll", throttle(() => {
  console.log("posisi", window.scrollY);
}, 300));

Scroll terus selama 1 detik memicu event kira-kira tiap 16 ms, sekitar 60 event. Dengan throttle 300 ms, handler jalan di ms ke-0, 304, 608, dan 912: 4 kali, dan tetap jalan berkala selama scroll berlangsung. Debounce 300 ms di situasi yang sama baru jalan sekali, 300 ms setelah scroll berhenti.

Leading dan trailing edge

Edge artinya kapan function jalan dalam satu rombongan event: di awal (leading) atau di akhir (trailing).

Library seperti Lodash punya opsi { leading, trailing } untuk keduanya.

Pilih yang mana

Situasi Pilih Kenapa
Kolom pencarian, request ke server debounce cukup hasil untuk kata terakhir
Simpan draft otomatis debounce simpan setelah orangnya berhenti mengetik
Scroll yang memanggil API selama scroll berlangsung throttle butuh update berkala selama bergerak
Resize jendela, lalu hitung ulang layout debounce cukup sekali setelah selesai
Posisi pointer saat drag throttle harus terus mengikuti gerakan

Patokannya: debounce menunggu aktivitasnya berhenti, throttle membatasi frekuensinya per interval.

⚠️ Jebakan yang sering ketemu

TL;DR: Debounce menunda function sampai event-nya berhenti selama delay ms: tiap panggilan menjalankan clearTimeout(timer) lalu timer = setTimeout(() => fn.apply(this, args), delay), jadi yang jalan cuma panggilan terakhir dengan argumennya ("sate" diketik 4 huruf, 1 request). Throttle menjalankan function paling banyak sekali per interval selama event terus datang (scroll 1 detik dengan throttle 300 ms jalan 4 kali). Leading berarti jalan di awal rombongan, trailing di akhirnya. Pakai debounce untuk pencarian, draft, dan resize. Pakai throttle untuk scroll dan drag yang butuh update selama bergerak.

Yang akan kamu pelajari