Debouncing vs Throttling
Two of the most important JavaScript performance optimization techniques.
What is Debouncing?
Debouncing delays execution until events stop for a configured pause. It is ideal when only the user's final intent matters.
What is Throttling?
Throttling limits execution frequency while events continue firing. It keeps expensive work predictable during continuous activity.
When should each be used?
Use debounce for search, product lookup, address lookup, and API requests. Use throttle for infinite scroll, resize, mouse tracking, and analytics events.
Keystrokes Count
0
API Calls Count
0
Saved Requests
0
Pause Behavior
500ms
API executes only after typing stops
GET /api/products?q=No request yet
Each keypress resets the timer. The function executes once after the final pause.
User Types
User Types
User Types
Waiting...
Execute Once
Copy-ready implementations
Runs once after the user stops triggering the event.
function debounce(fn, delay = 500) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}Adds leading, cancel, and flush behavior for production interfaces.
function debounce(fn, delay = 500, options = {}) {
let timeoutId;
let lastArgs;
let lastThis;
let result;
const leading = Boolean(options.leading);
function invoke() {
result = fn.apply(lastThis, lastArgs);
lastArgs = undefined;
lastThis = undefined;
return result;
}
function debounced(...args) {
const shouldCallNow = leading && !timeoutId;
lastArgs = args;
lastThis = this;
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
timeoutId = undefined;
if (!leading) invoke();
}, delay);
if (shouldCallNow) return invoke();
return result;
}
debounced.cancel = () => {
clearTimeout(timeoutId);
timeoutId = undefined;
};
debounced.flush = () => {
if (!timeoutId) return result;
clearTimeout(timeoutId);
timeoutId = undefined;
return invoke();
};
return debounced;
}Runs at most once per interval while events continue firing.
function throttle(fn, interval = 500) {
let lastRun = 0;
return function (...args) {
const now = Date.now();
if (now - lastRun >= interval) {
lastRun = now;
fn.apply(this, args);
}
};
}Supports leading and trailing calls so the final event is not lost.
function throttle(fn, interval = 500, options = {}) {
let lastRun = 0;
let timeoutId;
let lastArgs;
let lastThis;
const leading = options.leading !== false;
const trailing = options.trailing !== false;
function invoke(time) {
lastRun = time;
timeoutId = undefined;
fn.apply(lastThis, lastArgs);
lastArgs = undefined;
lastThis = undefined;
}
return function throttled(...args) {
const now = Date.now();
if (!lastRun && !leading) lastRun = now;
const remaining = interval - (now - lastRun);
lastArgs = args;
lastThis = this;
if (remaining <= 0 || remaining > interval) {
if (timeoutId) clearTimeout(timeoutId);
invoke(now);
return;
}
if (trailing && !timeoutId) {
timeoutId = setTimeout(() => invoke(Date.now()), remaining);
}
};
}Product Search
Apply debounce so catalog search, suggestions, pricing, and inventory requests wait for the shopper's final query.
Scroll Tracking
Apply throttle so product listing engagement is measured without flooding analytics pipelines.
Checkout Analytics
Apply throttle so shipping, payment, and validation events stay observable without slowing checkout.
Questions with detailed answers
What is the difference between debounce and throttle?
Debounce waits for a quiet period and then runs once with the final event. Throttle runs at a fixed maximum frequency while events keep happening. Debounce is about final intent; throttle is about steady, controlled updates.
When should debounce be used?
Use debounce when intermediate events are noise and only the final value matters. Search autocomplete, product search, address lookup, autosave, and expensive validation are common examples.
When should throttle be used?
Use throttle when the UI or analytics system needs periodic updates during continuous activity. Infinite scroll, resize handling, mouse tracking, scroll-depth analytics, and checkout telemetry are good fits.
Can debounce be implemented using throttle?
You can approximate pieces of one with the other, but they solve different timing contracts. A trailing-only throttle may look debounce-like in some cases, yet debounce resets the entire wait window after every event, while throttle preserves a fixed execution cadence.