The difference between debounce and throttle

The difference between debounce and throttle

Debounce and throttle are powerful techniques, but only if you really understand what they do. I often ask about them in tech interviews, and to my surprise, many developers (even seniors) struggle to explain the difference. The good news is: it’s actually quite simple. In this post, I’ll break down both techniques and share some practical use cases. If you are unfamiliar with the techniques and are asked about them too in your interview (I know, others are asking the same question in their interviews) you came to the right place!

The techniques

Debounce

Debouncing is probably the most familiar technique when it comes to controlling how often a function runs. In short, it limits the frequency of method execution, but it does a bit more than just what a setInterval could do. Instead of calling a function immediately on every event, debounce waits until the event has stopped firing for a set period of time, and then runs it once. There’s a catch: if the event fires again within that delay, debounce resets itself and starts the timer over.

Here’s an example that fires a lot if implemented normally:

window.addEventListener("resize", () => {
  console.log("Resized!");
});

Every time you resize the window, this callback runs. Resize continuously and it fires dozens of times per second. If the callback does something expensive, like an XHR request or heavy calculation, your performance could suffer. Debounce solves this by executing the callback only after a certain amount of idle time in milliseconds. The same example using debounce looks like this:

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

window.addEventListener("resize", debounce(() => {
  console.log("Resized (debounced)!");
}, 300));

The difference is simple but powerful. While you’re actively resizing, the callback doesn’t run at all. Only 300ms after you stop resizing does the console log appear once, no matter how many resize events were fired in between. This makes debounce a perfect tool for improving performance and keeping event-driven code efficient.

Throttle

Throttling is another technique for controlling how often a function runs, but it works a bit differently than debounce. Instead of waiting for the event to stop, throttle ensures the function runs at most once every X milliseconds, no matter how many times the event fires in between. Think of it as putting a speed limit on how often your callback can execute.

Here’s an example without throttle:

window.addEventListener("scroll", () => {
  console.log("Scrolling!");
});

If you scroll continuously, this callback fires dozens of times per second. If the callback performs heavy operations, like updating the DOM or fetching data, your page could lag. Throttling fixes this by limiting the execution rate. Here’s a simple throttle implementation:

const throttle = (fn, limit) => {
  let lastCall = 0;
  return (...args) => {
    const now = Date.now();
    if (now - lastCall >= limit) {
      lastCall = now;
      fn(...args);
    }
  };
};

window.addEventListener("scroll", throttle(() => {
  console.log("Scrolling (throttled)!");
}, 300));

The difference is subtle but important. Even if the scroll event fires continuously, the callback only runs once every 300ms, keeping your code efficient and your UI smooth. Unlike debounce, throttle doesn’t wait for the event to stop, it just spreads out the execution over time.

The difference between debounce and throttle

The key difference between debounce and throttle is how they control function execution over time. Debounce waits until an event has stopped firing for a certain period before running the function, and it resets the timer each time the event fires again. Throttle, on the other hand, ensures the function runs at regular intervals, no matter how often the event occurs, effectively spreading out the executions over time. In other words, debounce focuses on delaying until the action stops, while throttle focuses on limiting the rate of execution.

Use cases

Use cases for using debounce

  • Search input: Wait until the user stops typing before firing a request to a search API, avoiding unnecessary calls.
  • Window resize: Run layout recalculations or rendering updates only after the user has finished resizing the window.
  • Form validation: Validate inputs only after the user pauses typing, preventing constant re-validation.
  • Autocomplete suggestions: Trigger suggestion fetching once the user pauses typing rather than on every keystroke.
  • Text area or editor input: Save draft content after the user stops typing, rather than on every character change.

Use cases for using throttle

  • Scroll events: Limit how often a function runs while scrolling, for example updating a sticky header or a progress indicator.
  • Window resize: Adjust layouts or recalculate positions at a fixed interval instead of on every pixel of resizing.
  • Mouse movement tracking: Track cursor position for animations or interactions without overwhelming the system.
  • Infinite scrolling / lazy loading: Check for content load positions at a controlled interval while the user scrolls.
  • Rate-limited API calls: Ensure a function triggers requests at a maximum rate to prevent exceeding API limits.

Join the discussion

  • Eric P posted on the 9th of juli 2025

    I actually got asked this exact question during a tech interview last week, and I totally blanked on the difference between debounce and throttle. I remembered the general idea but couldn’t articulate it clearly under pressure. After the interview, I Googled it right away and ended up here, this post explains it better than any documentation I’ve seen so far. Wish I had read it a day earlier! Definitely bookmarking this one for future interviews. Thanks Jasper

  • Maya Lin posted on the 16th of juli 2025

    This article is great, but it also made me wonder if you can’t confidently explain the difference between debounce and throttle, can you really call yourself a frontend developer? It’s not some obscure trick, it's core to writing performant frontend code.

  • f1deu posted on the 5th of september 2025

    At the examples you list window resizing in both lists. What do you suggest for my use case: I want to reposition my chat widget. My guess is debounce, since it is after resizing? Thanks in advance

Leave a comment

Read more about:

Mastering code reviews as junior developer

Pull requests, merge requests, and code reviews. You’ve probably heard these terms before. A code review is the moment developers ask each other for feedback. A bugfix or new feature is finished, and before it can go live, someone else takes a look. Even if the change works functionally, there’s often room to…

Continue reading

10 JavaScript one-liners every developer should know

Code should be readable and pragmatic. For me, that means when I look at a piece of code, I should almost instantly understand what it does. Clear code always has good variable names, is predictable, avoids unnecessary logic, and lives in the right place within a project. But sometimes you need to do something a little complex without turning the rest of your code into a mess. That’s where one-liners come in. Small, pragmatic snippets…

Continue reading

The paradox of AI in web development

Since the start of my career as a developer, I’ve seen a lot of changes. From the rise of Dreamweaver with a WYSIWYG editor for generating table code to the arrival of jQuery and professional frameworks that completely transformed web development. Nowadays, there seems to be only one buzzword everywhere: AI.…

Continue reading