MediumMicrosoftAmazonGoogleServicenowTikTokUberLinkedin

Throttle

Prompt

Implement a throttle function that takes a callback function and a delay in milliseconds, and returns a throttled version of it.

The returned function should forward all arguments to the original callback.

Playground

Hint 1

Unlike debounce which delays execution, throttle allows the first call to go through immediately. The challenge is preventing subsequent calls within the delay window.

Hint 2

You need a boolean flag that tracks whether the function is currently in its "cooldown" period. While the flag is true, new calls are ignored.

Hint 3

After executing the function, set the flag to true and use setTimeout to flip it back to false after the delay. New calls should only execute when the flag is false.

Solution

Explanation

Throttling enforces a maximum number of times a function can be called over time.

Imagine a button that makes an API call when clicked. A user might click it 10 times in a second, but you only want to make one API call per second. Without throttling, every single click would fire an API call. Throttle lets the first click go through immediately, then ignores all subsequent clicks until the cooldown period is over.

The solution

function throttle(fn, delay) {
let isThrottled = false;

return function (...args) {
if (isThrottled) return;

// Save the context of 'this'
const context = this;

// Execute fn with the correct context and arguments
fn.apply(context, args);
isThrottled = true;

setTimeout(() => {
isThrottled = false;
}, delay);
};
}

We use a boolean flag isThrottled that acts like a gate. When the throttled function is called:

  • If isThrottled is false, the gate is open. We run the original function, then close the gate by setting isThrottled = true. We also start a timer that will reopen the gate after delay milliseconds.

    You'll also notice we use const context = this; alongside fn.apply(context, args) here instead of just fn(...args). This is actually a super crucial detail! It ensures that the throttled function perfectly remembers its this context. This comes up a lot if you're attaching the throttled function to an object or a DOM element. By explicitly saving the context and using apply(context, args), we're saying, "Make sure the original function gets exactly the same context and arguments." This extra polish really shows interviewers you've mastered the nuances of JavaScript.

  • If isThrottled is true, the gate is closed. We do nothing and return immediately.

Once the setTimeout fires, isThrottled flips back to false, and the next call will go through again.

Debounce vs Throttle

These two are always asked together in interviews, so it's worth knowing the difference.

Debounce waits until the caller stops calling, then fires once. If you keep calling, it keeps resetting the timer and never fires until you're quiet for the full delay.

Throttle fires immediately on the first call, then ignores calls for the next delay milliseconds. It guarantees at most one execution per time window.

A practical way to remember: debounce is for search inputs (wait until the user finishes typing), throttle is for scroll handlers (fire at a steady rate while scrolling, but not on every pixel).

You'll often see throttle used with scroll events, resize handlers, and rate-limited button clicks. Any situation where you want steady, evenly-spaced executions rather than waiting for silence.