Frontend performance: debounce and throttle
Preface
Looking back, when I first ran into debounce and throttle, I thought “what kind of weird jargon is this, why make things so complicated?” After a quick search I learned they are solutions for improving performance and avoiding stack overflow, and after that, whenever I ran into a similar feature, I would just reach for lodash.debounce and call it a day.
Recently, while refactoring an older project at the new company, I noticed many places that did not use debounce/throttle for optimization. Using them again and again, I suddenly realized I was not actually that clear on the difference between the two. So this post is a way to walk myself through what each one does and the common scenarios where they are used.
throttle
The official definition is that throttle makes a function execute only once within a given period of time, and it executes continuously. Common scenarios include window scroll and window resize, basically continuous events. The main goal is to avoid stack overflow caused by scroll/resize firing too frequently.
throttle demo:
funtion throttle( targetFunc, limitPeriod ){
let inThrottle;
return function()=>{
const args = arguments;
const context = this;
if (!isThrottle) {
targetFunc.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
throttle demo with arrow function
funtion throttle( targetFunc, limitPeriod ){
let inThrottle;
return (...args)=>{
if (!inThrottle) {
targetFunc(...args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
Debounce
For debounce, the function is only executed after a period of time has passed, with the goal of capturing the last triggered event. Common scenarios are running a function from input changes or submitting a form. Window scroll/resize can also use debounce, but the goal there is to run the target event only after scroll/resize has stopped for a while.
debounce demo
function debounce( targetFunc, delayPeriod ){
let inDebounce;
return function(){
const args = arguments;
const context = this;
clearTimeout(inDebounce);
inDebounce = setTimeout(() => targetFunc.apply(context, args), delayPeriod);
}
}
debounce demo with arrow function
function debounce( targetFunc, delayPeriod ){
let inDebounce;
return (...args)=>{
clearTimeout(inDebounce);
inDebounce = setTimeout(() => targetFunc( ...args), delayPeriod);
}
}
Ref
- lodash document: link
ChangeLog
- 20230627: init
- 20260501–translate by claude code