- Home
- /
- Tutorials
- /
- JavaScript Tutorial
- /
- JavaScript Debounce
JavaScript Performance
JavaScript Debounce
Debouncing delays a function until the calls have stopped for a while.
Typing in a search box can fire an event on every keystroke.
Debouncing waits until typing pauses before doing the expensive work.
Example
Example
javascript
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(function () {
fn(...args);
}, delay);
};
}
let calls = 0;
const debounced = debounce(function () { calls++; }, 10);
debounced();
debounced();
debounced();
console.log(calls);The output is 0: none of the calls have fired yet, because each reset the timer.
How Debounce Works
Every call cancels the previous pending timer and starts a new one.
The wrapped function only actually runs once calls stop for the delay period.
Rapid calls collapse into a single run at the end.
Syntax
Syntax
javascript
const debounced = debounce(expensiveFunction, 300);300 milliseconds is a common delay for search input.
Only the Last Call Survives
Each new call resets the clock, so only the final one gets through.
Example
Example
javascript
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(function () { fn(...args); }, delay);
};
}
const received = [];
const debounced = debounce(function (value) { received.push(value); }, 10);
debounced("a");
debounced("b");
debounced("c");
console.log(received.length);Nothing has run yet; all three calls only reset the timer.
Waiting for It to Fire
After the delay has genuinely passed with no new calls, it runs once.
Example
Example
javascript
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(function () { fn(...args); }, delay);
};
}
function afterDelay(ms, callback) {
setTimeout(callback, ms);
}
let received = null;
const debounced = debounce(function (value) { received = value; }, 5);
debounced("first");
debounced("final");
afterDelay(20, function () {
console.log(received);
});The output is final, once the delay has actually passed.
Search Input
This is the classic use: wait until the visitor pauses typing.
Example
Example
javascript
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(function () { fn(...args); }, delay);
};
}
let searchCount = 0;
const search = debounce(function (query) { searchCount++; }, 10);
search("j");
search("ja");
search("jav");
search("java");
console.log(searchCount);Typing four letters triggered zero searches so far - only the pause after triggers one.
Window Resize
Resizing fires constantly; debouncing waits until it settles.
Example
Example
javascript
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(function () { fn(...args); }, delay);
};
}
let layoutRuns = 0;
const recalculateLayout = debounce(function () { layoutRuns++; }, 10);
for (let i = 0; i < 20; i++) {
recalculateLayout();
}
console.log(layoutRuns);Twenty resize events, and the expensive layout work has not run even once yet.
Passing Arguments Through
The wrapper forwards whatever it was called with to the real function.
Example
Example
javascript
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(function () { fn(...args); }, delay);
};
}
function afterDelay(ms, callback) {
setTimeout(callback, ms);
}
let lastQuery = null;
const search = debounce(function (query) { lastQuery = query; }, 5);
search("hello world");
afterDelay(20, function () {
console.log(lastQuery);
});The output is hello world.
Complete Example
Complete Example
html
<!DOCTYPE html>
<html>
<head>
<title>JavaScript Debounce</title>
</head>
<body>
<h1>Debounce</h1>
<input id="search" placeholder="Type to search">
<p id="out">Waiting...</p>
<script>
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(function () { fn(...args); }, delay);
};
}
const runSearch = debounce(function (value) {
document.getElementById("out").textContent = "Searched for: " + value;
}, 300);
document.getElementById("search").addEventListener("input", function (event) {
runSearch(event.target.value);
});
</script>
</body>
</html>Try It Yourself
Run the above example in the Try It Editor.
Try typing fast:
Type quickly and notice the search only fires after you pause.
Important Points
- Debounce delays a function until calls have stopped for a while.
- Each new call resets the timer.
- Only the last call in a burst actually runs.
- Useful for search input and window resize.
- Arguments are forwarded to the wrapped function.
Conclusion
Debounce turns a flood of events into one meaningful call.
Search boxes and resize handlers are the two places you will use it most.
The next lesson covers throttle, which solves a related but different problem.
