Debouncing, Throttling & Performance Patterns
18 min read
DebounceThrottlerequestAnimationFrameWeb WorkersrequestIdleCallbackPerformanceRate Limiting
Controlling Function Execution Rate
Debounce
Wait until the user stops performing an action for a specified delay before executing.
Use case: Search input, window resize, form validation.
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// Usage: Only search after user stops typing for 300ms
const search = debounce((query) => {
fetch(`/api/search?q=${query}`);
}, 300);
input.addEventListener("input", (e) => search(e.target.value));Throttle
Execute at most once per specified interval, regardless of how many times it's triggered.
Use case: Scroll events, mouse move, API rate limiting.
function throttle(fn, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
lastTime = now;
fn.apply(this, args);
}
};
}
// Usage: Update scroll position at most every 100ms
window.addEventListener("scroll", throttle(() => {
updateScrollProgress();
}, 100));Debounce vs Throttle
| Feature | Debounce | Throttle |
|---|---|---|
| Execution | After action stops | During action, periodically |
| Best for | Search, validation | Scroll, resize, drag |
| User types fast | Fires once at the end | Fires every N ms |
requestAnimationFrame
// Smooth animation at 60fps
function animate(element) {
let position = 0;
function step() {
position += 2;
element.style.transform = `translateX(${position}px)`;
if (position < 300) {
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
}Web Workers for Heavy Computation
// main.js
const worker = new Worker("worker.js");
worker.postMessage({ data: largeArray });
worker.onmessage = (e) => {
console.log("Result:", e.data);
};
// worker.js
self.onmessage = (e) => {
const result = heavyComputation(e.data);
self.postMessage(result);
};requestIdleCallback
// Run non-critical tasks when browser is idle
requestIdleCallback((deadline) => {
while (deadline.timeRemaining() > 0) {
doNonCriticalWork();
}
});