Implement debounce function
What is debouncing a function?
Debouncing is a method or a way to execute a function when it is made sure that no further repeated event will be triggered in a given frame of time.
A technical example is when we search something on any eCommerce site, we don’t want to trigger a search function and make a request to the server as the user keeps typing each letter. We want the user to finish typing and then wait for a specified window of time to see if the user is not going to type anything else or has finished typing then make the request and return the result.
Excessively invoking the function majorly hampers the performance and is considered as one of the key hurdles.
Implementation
const debounce = (func, delay) => {
// 'private' variable to store the instance
// in closure each timer will be assigned to it
let inDebounce;
// debounce returns a new anonymous function (closure)
return function() {
// reference the context and args for the setTimeout function
const context = this;
const args = arguments;
// base case
// clear the timeout to assign the new timeout to it.
// when event is fired repeatedly then this helps to reset
clearTimeout(inDebounce);
// set the new timeout and call the original function with apply
inDebounce = setTimeout(() => func.apply(context, args), delay);
};
};
Explanation
We created a function that will return a function. The outer function uses a variable to keep track of timerId for the execution of the inner function.
The inner function will be called only after a specified window of time, to achieve this we use setTimeout function.
We store the reference of the setTimeout function so that we can clear it if the outer function is re-invoked before the specified time clearTimeout(inDebounce) and again recall it.
If we are invoking for the first time, our function will execute at the end of our delay. If we invoke and then reinvoke again before the end of our delay, the delay restarts.
Test Case
Input:
// print the mouse position
const onMouseMove = (e) => {
console.clear();
console.log(e.x, e.y);
}
// define the debounced function
const debouncedMouseMove = debounce(onMouseMove, 50);
// call the debounced function on every mouse move
window.addEventListener('mousemove', debouncedMouseMove);
Output:
300 400
Implement debounce function with Immediate Flag
Debouncing is a method or a way to execute a function when it is made sure that no further repeated event will be triggered in a given frame of time.
In the last example we had seen how to implement the classic debounce function with delay. In this implementation we will add one extra flag called immediate to execute the function immediately without any further delay. After initial execution it won’t run again till the delay.
This flag will be optional which means if it is set to false then the debounce function will behave normally.
Implementation
const debounce = (func, wait, immediate) => {
// 'private' variable to store the instance
// in closure each timer will be assigned to it
let timeout;
// debounce returns a new anonymous function (closure)
return function() {
// reference the context and args for the setTimeout function
let context = this,
args = arguments;
// should the function be called now? If immediate is true
// and not already in a timeout then the answer is: Yes
const callNow = immediate && !timeout;
// base case
// clear the timeout to assign the new timeout to it.
// when event is fired repeatedly then this helps to reset
clearTimeout(timeout);
// set the new timeout
timeout = setTimeout(function() {
// Inside the timeout function, clear the timeout variable
// which will let the next execution run when in 'immediate' mode
timeout = null;
// check if the function already ran with the immediate flag
if (!immediate) {
// call the original function with apply
func.apply(context, args);
}
}, wait);
// immediate mode and no wait timer? Execute the function immediately
if (callNow) func.apply(context, args);
}
}
Explanation
We use a private variable to store the timerId, and return a closure from it which will execute the callback function after debouncing.
Inside the closure, store the context of the current function and its arguments and pass it later to the callback function while executing it with the help of apply method.
Also create a flag to check if the debounce should happen immediately or not const callNow = immediate && !timeout; this will help to execute the callback immediately only when it is not in the timeout and immediate flag is true.
Then assign the timer and execute the function only when the immediate flag is false.
At the end, execute the callback if callNow is true.
Test Case
Input:
// print the mouse position
const onMouseMove = (e) => {
console.clear();
console.log(e.x, e.y);
}
// define the debounced function
const debouncedMouseMove = debounce(onMouseMove, 50);
// call the debounced function on every mouse move
window.addEventListener('mousemove', debouncedMouseMove);
Output:
314 419
Happy Learning!!!