HuntExams Academy logo
JavaScriptAdvanced#performance#functions

What is debouncing and throttling?

Answer

Debouncing delays the call until activity stops for a set time — good for search inputs. Throttling guarantees at most one call per interval — good for scroll and resize handlers.

Example

function debounce(fn, ms) {
  let t;
  return (...a) => { clearTimeout(t); t = setTimeout(() => fn(...a), ms); };
}
input.oninput = debounce(search, 300);

Detailed explanation

Debouncing and throttling control how often a function runs when events arrive rapidly. They matter because input, scroll, resize, and pointer events can trigger expensive work such as API requests, calculations, or DOM updates. Neither technique makes an individual operation faster; instead, each reduces unnecessary executions. The key distinction is whether you want to wait for a pause in activity or keep processing activity at a controlled rate.

Debouncing resets a waiting period whenever a new event arrives. With a trailing debounce of 300 ms, the function becomes eligible to run only after no new event has arrived for 300 ms. In the supplied implementation, a closure stores the timer identifier, clearTimeout cancels the pending callback, and setTimeout schedules another callback with the latest arguments. This suits search suggestions: typing several characters quickly produces one search after the user pauses. During continuous activity, a basic trailing debounce may postpone execution indefinitely; some implementations provide maxWait to prevent that.

Throttling limits execution frequency while events continue. For example, a leading-only throttle with a 200 ms cooldown runs immediately, then ignores calls until that cooldown expires. A throttle with trailing execution can also retain the latest arguments and process them when its scheduling rules allow. Implementations commonly track the last execution time, maintain a timer, or combine both approaches. Throttling suits periodic scroll-position updates or resize feedback during interaction. Exact boundary behaviour depends on the implementation, so clarify leading and trailing options rather than assuming every throttle behaves identically.

Interviewers typically expect the distinction, a suitable use case, and awareness of implementation details. The supplied debounce forwards arguments but does not preserve a caller's dynamic this because it returns an arrow function. A reusable version can return a normal function and invoke fn.apply(this, args) inside its timer callback. Also, timers specify a minimum scheduling delay, not an exact execution time: a busy event loop can delay execution. For asynchronous search, debouncing alone does not prevent older responses from overwriting newer results.

Key points to remember

  • Debouncing waits for inactivity; throttling limits execution frequency during ongoing activity.
  • A trailing debounce cancels and replaces its pending timer on every call.
  • Leading and trailing options determine whether execution happens at the start, end, or both.
  • Use debounce for search or final resize work; use throttle for periodic scroll or resize updates.
  • Reusable wrappers should handle arguments, this binding, timer cleanup, and documented timing semantics.

Common mistakes candidates make

  • Saying debounce runs periodically during continuous events; a basic trailing debounce can keep waiting indefinitely.
  • Assuming all implementations execute immediately or preserve the final call without checking leading and trailing behaviour.
  • Recreating the wrapper on every event, which creates separate timer state and defeats rate control.

Likely follow-up questions

What are leading and trailing execution?

Leading execution invokes the function at the beginning of an activity window, while trailing execution schedules work at its end. Whether both occur for a single call depends on the implementation, so state the intended behaviour.

Does debouncing search requests prevent race conditions?

No; requests started after separate pauses can still overlap and finish out of order. Cancel obsolete requests with AbortController where supported, or use a request identifier to ignore stale responses.

When should requestAnimationFrame be used instead?

For visual updates, requestAnimationFrame schedules work before a browser repaint rather than using a fixed millisecond interval. Use a pending-frame flag to coalesce multiple events into one scheduled update; calling it repeatedly alone does not deduplicate callbacks.

Interview tip: Start with the pause-versus-rate distinction, give one example of each, and explain the timer stored in the debounce closure.

Related Interview Questions

1
JavaScriptBeginner#arrays

Explain map, filter and reduce.

Open
2
JavaScriptBeginner#arrays

Difference between forEach and map?

Open
3
JavaScriptBeginner#arrays

Difference between slice and splice?

Open