Debouncing and throttling events in JavaScript
Debouncing and throttling events in JavaScript

Debouncing and Throttling in JavaScript: A Practical Guide

Some events fire far more often than you want. A user typing in a search box triggers keyup on every keystroke; scrolling fires dozens of times a second; resizing a window is a firehose. If you run expensive work on every one of those events, your app janks. Debounce and throttle are the two techniques that tame this, and knowing which to use where is a genuinely useful skill.

Debounce: wait for the pause

Debouncing says: “do the work only after the events stop coming for a moment.” It is perfect for a search-as-you-type box — you do not want to hit the API on every letter, only once the user pauses.

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

searchInput.addEventListener('input',
  debounce(runSearch, 300));

Every keystroke resets the timer. The search only runs 300ms after the last one. Type “javascript” quickly and you make one request instead of ten.

Throttle: at most once per interval

Throttling says: “run at most once every N milliseconds, no matter how many events arrive.” It is the right tool for scroll and resize handlers, where you want steady updates but not hundreds per second.

function throttle(fn, interval) {
  let ready = true;
  return (...args) => {
    if (!ready) return;
    ready = false;
    fn(...args);
    setTimeout(() => { ready = true; }, interval);
  };
}

window.addEventListener('scroll',
  throttle(updateProgressBar, 100));

Now your scroll handler fires a maximum of ten times a second, which is smooth enough for a progress bar while sparing the browser.

The difference in one sentence

Debounce waits until the activity stops; throttle enforces a steady maximum rate during the activity. Search input wants the pause, so debounce. Scroll tracking wants regular sampling, so throttle. Keep that distinction and you will pick correctly every time.

Do not reinvent it in production

The versions above are great for understanding the idea, and honestly fine for small projects. But battle-tested implementations handle edge cases like leading/trailing calls and cancellation. Libraries such as Lodash ship debounce and throttle that have handled those corners for years, so reach for them in real apps.

Master debounce and throttle and a whole class of performance problems simply disappears. They are small functions with an outsized impact on how smooth your interface feels.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *