Volume 2

Q121: Debounce, Throttle and Rate Limiting

Difficulty: SeniorFrequency: HighAnswer time: 8-12 minutes

What Interviewers Want To Evaluate

This question checks whether you understand high-frequency events and controlled execution. Interviewers want debounce, throttle, leading and trailing calls, cancellation, search boxes, resize handlers, scroll work, request rate limiting, and UX trade-offs.

Senior answers should connect the pattern to real product behavior, not only write a utility from memory.

Short Interview Answer

Debounce delays work until activity has stopped for a period. It is useful for search input, autosave, and validation where only the final value matters. Throttle allows work at most once per interval. It is useful for scroll, resize, pointer movement, and progress updates where regular sampling matters. Rate limiting is a broader control that protects systems from too many operations over time. The right choice depends on whether the user needs final accuracy, continuous feedback, or system protection.

Detailed Interview Answer

High-frequency events can overwhelm the main thread, backend APIs, and UI state.

Examples include:

typing
scrolling
resizing
dragging
mousemove
input validation
autosave
analytics events

Debounce and throttle are ways to decide when work should run.

Debounce

Debounce waits until events stop.

function debounce(fn, delay) {
  let timeoutId;

  return function debounced(...args) {
    clearTimeout(timeoutId);

    timeoutId = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

Every call resets the timer. The function runs only after silence.

Debounce Use Cases

Debounce is good when intermediate values are not important.

Good examples:

search suggestions after typing pauses
email availability check
autosave after editing pauses
expensive form validation
window resize recalculation after resize ends

It reduces wasted work while preserving the final result.

Throttle

Throttle runs at most once per interval.

function throttle(fn, interval) {
  let lastRun = 0;

  return function throttled(...args) {
    const now = Date.now();

    if (now - lastRun >= interval) {
      lastRun = now;
      fn.apply(this, args);
    }
  };
}

This samples high-frequency calls at a controlled rate.

Throttle Use Cases

Throttle is good when continuous feedback matters.

Good examples:

scroll position tracking
resize progress
drag movement
pointer coordinates
analytics sampling
infinite-scroll distance checks

The user still gets updates during the interaction, just not for every raw event.

Leading and Trailing Behavior

Production debounce and throttle utilities often support leading and trailing behavior.

leading: run at the beginning of the window
trailing: run at the end of the window

For search, trailing debounce is common because the final value matters.

For a button that should respond immediately but ignore repeat clicks briefly, leading behavior may be better.

Cancel and Flush

Robust utilities often expose cancel and flush.

cancel: prevent scheduled work from running
flush: run pending work immediately

This matters during route changes, component unmount, modal close, or form submission.

Rate Limiting

Rate limiting is broader than debounce or throttle. It controls how much work can happen within a time window.

Examples:

maximum 10 requests per minute
maximum 1 submit per second
maximum 100 analytics events per session

Frontend rate limiting improves UX and reduces accidental load, but backend rate limiting is still required for enforcement.

Search Example

const search = debounce(async (query) => {
  if (!query.trim()) {
    return;
  }

  const results = await fetchResults(query);
  renderResults(results);
}, 300);

This avoids firing a request for every keystroke.

For real search, also handle cancellation or stale responses.

Scroll Example

const updateScrollProgress = throttle(() => {
  const progress = window.scrollY / document.body.scrollHeight;
  renderProgress(progress);
}, 100);

window.addEventListener("scroll", updateScrollProgress);

This keeps progress reasonably fresh without running on every scroll event.

Common Mistakes

A common mistake is using debounce for scroll progress. The user may see no updates until scrolling stops.

Another mistake is using throttle for search input. It may send unnecessary intermediate queries.

Another mistake is forgetting cleanup, which lets scheduled callbacks run after UI is gone.

Senior Trade-Offs

The choice depends on user expectation.

final answer matters: debounce
continuous feedback matters: throttle
system protection matters: rate limit
security or abuse control matters: backend enforcement

Good interviews mention cancellation, accessibility, perceived responsiveness, and stale UI risk.

Code or Design Example

function createDebouncedSearch(loadResults, render) {
  let controller;

  return debounce(async (query) => {
    controller?.abort();
    controller = new AbortController();

    const results = await loadResults(query, controller.signal);
    render(results);
  }, 300);
}

This combines debounce with request cancellation.

Debugging Workflow

When high-frequency behavior feels wrong:

identify the source event frequency
decide whether final or continuous feedback matters
check leading and trailing behavior
check cancellation on unmount or route change
check stale async results
measure main-thread cost
verify backend rate limits still exist

Interview Framing

Define debounce and throttle with one sentence each. Then give search and scroll examples. Add leading, trailing, cancel, and stale-request handling for senior depth.

Revision Notes

Debounce waits for silence. Throttle samples at a controlled interval. Rate limiting caps work over time.

Key Takeaways

These patterns are about user experience and system protection. Pick the timing model that matches the product behavior.

Follow-Up Questions

  1. What is debounce?
  2. What is throttle?
  3. When is debounce better than throttle?
  4. When is throttle better than debounce?
  5. What is leading behavior?
  6. What is trailing behavior?
  7. Why do debounced callbacks need cancellation?
  8. How do stale async responses happen?
  9. Is frontend rate limiting enough for security?
  10. How would you test debounce?

How I Would Answer This In A Real Interview

I would say debounce waits until activity stops, while throttle runs at most once per interval. Then I would map debounce to search and autosave, throttle to scroll and resize, and mention cancellation, stale responses, leading/trailing behavior, and backend rate limits.