Throttling
Introduction
Throttling limits a function so it can run at most once per time window. Unlike debounce, it does not wait for silence; it permits periodic execution while calls continue.
This is a favorite interview problem because it looks similar to debounce but has a different timeline, different edge cases, and different leading and trailing semantics.
Why This Matters
Throttle is the right tool for continuous streams where the UI should update regularly but not excessively: scroll position, drag movement, resize progress, pointer tracking, and telemetry sampling. It also maps cleanly to backend rate-limiting ideas.
Theory
Mental model
A throttled function opens a time window after it runs. Calls inside that window are ignored or saved as the trailing call, depending on options. When the window ends, the saved latest call may run.
Leading and trailing
Leading throttle runs immediately when the first call arrives. Trailing throttle remembers the latest call during the wait window and runs it at the end. Many production utilities enable both, giving immediate feedback and one final update with the latest data.
Debounce comparison
Debounce compresses a burst into one call after silence. Throttle samples a burst at a controlled rate. If calls keep arriving for five seconds, debounce may run once at the end; throttle may run many times, but no more often than the interval.
Implementation approaches
Timestamp-only throttle is simple but may drop the final call. Timer-assisted throttle can support trailing execution with the latest arguments.
Visual Diagrams
calls: A -- B -- C -- D -- E window: [100ms] [100ms] [100ms] leading only output: A D leading plus trailing: A C E
Throttle samples a burst instead of waiting for complete silence.
Code Examples
Throttle with leading and trailing behavior
This timer-assisted version keeps the latest call for the trailing edge.
Playground
Press Run to execute the code and see output here.
Output Prediction
Predict the output #1
1function makeThrottle(fn, wait) {2 var lastTime = -Infinity;3 return function (value, time) {4 if (time - lastTime >= wait) {5 lastTime = time;6 fn(value);7 }8 };9}10 11var log = makeThrottle(function (value) {12 console.log(value);13}, 100);14 15log('A', 0);16log('B', 50);17log('C', 100);18log('D', 150);19log('E', 220);Coding Exercises
Implement throttle with leading and trailing options
HardWrite throttle(fn, wait, options) where leading and trailing default to true. Preserve the latest arguments for trailing execution and expose .cancel().
Interview Questions
1When would you choose throttle instead of debounce?
Choose throttle when work should continue at a controlled rate during ongoing activity, such as scroll progress or drag updates. Choose debounce when only the final value after a pause matters.
Follow-ups
- How do you implement trailing throttle?
- What happens if both leading and trailing are false?
2Why does timestamp-only throttle often miss the final event?
Because it only runs when a call arrives after the interval has elapsed. If the final call happens inside the interval and no later call arrives, there is no timer to execute it later.
Quiz
1. Which statement correctly describes throttle?
Summary
- Throttle limits a function to a maximum execution rate.
- Leading throttle gives immediate feedback; trailing throttle preserves the latest update in the window.
- Debounce waits for silence; throttle samples continuous activity.
- Timer-assisted throttle is needed when the final call should not be lost.
Cheat Sheet
Throttle: run at most once per wait.
Use for: scroll, resize progress, dragging, telemetry.
Leading: first call runs now.
Trailing: latest call runs when the window closes.
Contrast: debounce waits for silence; throttle samples activity.