Skip to Content
Course content

136: Debouncing and Throttling

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I was working on a search feature yesterday, and I noticed something frustrating. Every single keystroke the user typed was triggering a fetch request to the backend. If someone typed "JavaScript", that's 10 API calls in about two seconds. It's a waste of server resources, and if the responses come back out of order, the UI starts flickering like crazy.

The API Spam Problem

Let's look at what happens when we just attach a listener to an input field. I'll write a simple function that simulates a database lookup.

const searchInput = document.querySelector('#search');

function performSearch(query) {
  console.log(`Searching for: ${query}...`);
  // Imagine a fetch() call here
}

searchInput.addEventListener('input', (e) => {
  performSearch(e.target.value);
});

If you try this, you'll see the console explode. Every time you hit a key, the function runs. Now, I don't actually care what the user is searching for until they've stopped typing for a moment. I want to wait for a pause.

Waiting for the Silence

My first instinct is to use a timer. I'll wrap the search call in a setTimeout. I figure, "Okay, wait 300ms before searching."

searchInput.addEventListener('input', (e) => {
  setTimeout(() => {
    performSearch(e.target.value);
  }, 300);
});

But wait—this didn't actually fix the number of calls. It just delayed them. If I type "JavaScript", I still get 10 logs; they just all happen 300ms later. This is where the "debounce" pattern comes in. The trick is to cancel the previous timer every time a new keystroke happens.

let timer;

searchInput.addEventListener('input', (e) => {
  // Clear the previous timer if it's still running
  clearTimeout(timer);

  // Start a new timer
  timer = setTimeout(() => {
    performSearch(e.target.value);
  }, 300);
});

Now we're talking. If I type quickly, the timer keeps getting reset. The search only actually triggers once I stop typing for at least 300ms. That's debouncing: grouping a burst of events into a single execution.

The Jank of the Scroll

Now, let's try to apply that same logic to a different problem. Imagine I'm building a "progress bar" that fills up as the user scrolls down a long page. I'll use the same debounce logic to keep the performance high.

let timer;
window.addEventListener('scroll', () => {
  clearTimeout(timer);
  timer = setTimeout(() => {
    console.log('Updating progress bar...');
    // Update DOM here
  }, 300);
});

This feels... wrong. If I scroll continuously, the progress bar doesn't move at all until I completely stop scrolling. It's janky. In this case, I don't want to wait for the "silence" at the end; I want regular updates while the action is happening, just not 60 times per second.

Keeping a Steady Beat

This is where we need throttling. Instead of resetting a timer, I need a way to say, "I've executed this function; now ignore all requests for the next 300ms, regardless of how many times the user scrolls."

I'll use a boolean flag to keep track of whether we are currently in a "waiting" period.

let isWaiting = false;

window.addEventListener('scroll', () => {
  if (isWaiting) return; // Skip this call if we're still waiting

  console.log('Updating progress bar...');
  isWaiting = true;

  setTimeout(() => {
    isWaiting = false; // Open the gate again after 300ms
  }, 300);
});

Now, if I scroll for five seconds, the progress bar updates consistently every 300ms. It's smooth enough for the eye, but it doesn't choke the main thread. To sum up the difference in my head: Debouncing is like a door that won't open until people stop crowding it; Throttling is like a turnstile that only lets one person through every few seconds.




📋 Practical Task

Build a Throttled Window Dimension Tracker

Create a webpage that displays the current window width and height in a <div>. Attach an event listener to the resize event of the window to update these numbers. However, window resize events fire incredibly fast. Your task is to implement a throttle function (or logic) that ensures the DOM only updates at most once every 200ms, regardless of how fast the user drags the window corner.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.