/* javascript */

Debouncing vs Throttling, With Actual Numbers

the sutra

Debounce waits for silence. Throttle keeps a steady beat.

Type "debounce vs throttle" into any search engine and you will get diagrams. Here is the version with numbers attached, which is usually what actually makes it stick.

Debounce: wait for a pause

A search-as-you-type box firing an API call on every keystroke will fire 10+ requests for a 10-character word. Debounce says: wait until the user stops typing for, say, 300ms, then fire once.

function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

searchInput.addEventListener(
  "input",
  debounce((e) => fetchResults(e.target.value), 300)
);

Type "react" fast: five keystrokes, zero requests fire until 300ms after the last one — so exactly one request, for "react".

Throttle: enforce a steady maximum rate

A scroll handler updating a "reading progress" bar needs to run repeatedly, just not on every single scroll event (which can fire 60+ times a second). Throttle says: run at most once every N milliseconds, no matter how often the event fires.

function throttle(fn, limit) {
  let waiting = false;
  return (...args) => {
    if (waiting) return;
    fn(...args);
    waiting = true;
    setTimeout(() => (waiting = false), limit);
  };
}

window.addEventListener(
  "scroll",
  throttle(() => updateProgressBar(), 100)
);

Scroll continuously for 2 seconds: instead of 120+ calls, you get roughly 20, evenly spaced — the bar stays smooth without hammering the layout.

The rule of thumb

If the ideal outcome is "run once, after things settle" — search boxes, resize handlers, form validation — debounce. If the ideal outcome is "run regularly, but not too regularly" — scroll position, mouse-move effects, live progress — throttle. Reaching for the wrong one either delays a search that should have felt instant, or floods a rate-limited API that should have been eased off.

more in javascript