What Is Debouncing?
Debouncing means waiting until a user has stopped doing something before executing a function. If a user types in a search box and you search on every keystroke, you'll fire dozens of API calls. With debouncing, you wait until they pause typing (e.g. 300ms of inactivity) then fire once.
Basic Debounce Function
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
How it works: every call clears the previous timer and starts a new one. The wrapped function only runs when the timer completes without being reset.
Usage Examples
// Search input — wait 300ms after user stops typing
const searchInput = document.getElementById('search');
const handleSearch = debounce(function(e) {
const query = e.target.value;
fetchResults(query); // API call
}, 300);
searchInput.addEventListener('input', handleSearch);
// Window resize — wait 200ms after resize stops
const handleResize = debounce(function() {
recalculateLayout();
}, 200);
window.addEventListener('resize', handleResize);
// Save draft automatically
const editor = document.getElementById('editor');
const saveDraft = debounce(async function() {
const content = editor.value;
await fetch('/api/save-draft', {
method: 'POST',
body: JSON.stringify({ content }),
headers: { 'Content-Type': 'application/json' }
});
console.log('Draft saved');
}, 1000); // save 1 second after user stops typing
editor.addEventListener('input', saveDraft);
Debounce vs Throttle
| Technique | Behaviour | Best For |
|---|---|---|
| Debounce | Fires once after activity stops | Search inputs, form validation, save drafts |
| Throttle | Fires at most once per interval | Scroll events, mouse move, game loops |
// Throttle implementation
function throttle(fn, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
lastTime = now;
fn.apply(this, args);
}
};
}
// Throttle scroll handler — fires max once per 100ms
window.addEventListener('scroll', throttle(updateScrollProgress, 100));
Using a Library
If you're already using Lodash, use its optimised implementations:
import { debounce, throttle } from 'lodash';
const handleSearch = debounce((e) => fetchResults(e.target.value), 300);
const handleScroll = throttle(() => updateNav(), 100);