What are Debounce and throttle ? They are techniques for optimizing browser performance in JS. Why we use them ? These are for limiting the rate of function execution/API request
Where can we use them ? Input/button/window events, Searching/ Typeahead, Save as user inputs, hover actions, interactions while scrolling
11. Basic Debounce()
Function:
debounce(function, delay)
Description: Schedules a trigger for an event after specific interval.
Polyfill JS, HTML, Usecase result: Basic Debounce
/**
* @param {Function} customBasicDebounce
* @param {Function} func
* @param {number} millisec delay
*/
//What are we doing here?
//1. Set the context
//2. If the timer exist, then clear the timer before calling the function
//3. If not, call the function
function customBasicDebounce(func, delay = 400) {
//initalizing timer here - closure
let timer;
return ((...args) => {
//clearing timer before calling again for restricting multiple instances of timer
clearTimeout(timer);
//calls the function after delay
timer = setTimeout(() => func.apply(this, ...args), delay);
});
}
12. Debounce with leading & trailing options
Function:
debounce(callback, delay, option={leading:false, trailing: true})
Description: In short, If leading -> Capture initial click after delay, if trailing -> Capture latest click after a delay
Polyfill JS, HTML, Usecase result: Debounce Leading & Trailing
/**
* @param {Function} func
* @param {number} delay
* @param {boolean} option.leading
* @param {boolean} option.trailing
*/
//What are we doing here?
//1. Set the context and trailing arguments
//2. If not leading/trailing, return null
//3. If timer is done but leading is true, invoke the func execution
//4. If not, save the context for later execution
//5. clear the timer to avoid multiple timer instances
//6. call the timer if trailing is true n trailing args exists
//7. Reset the timer and args
function customAdvancedDebounce(func, delay, option = { leading: false, trailing: true }) {
let timer = null; // same like basic debounce
let trailingArgs = null; // as we require last arguments for trailing
if (!option.leading && !option.trailing) return () => null; //if both false, return null
return function debounced(...args) { //returns a debounced function
if (!timer && option.leading) { // timer done but leading true
func.apply(this, args); //call func
} else {
trailingArgs = args; // arguments will be the last args
}
clearTimeout(timer); //clear timer for avoiding multiple timer instances
timer = setTimeout(() => {
if (option.trailing && trailingArgs) func.apply(this, trailingArgs); // trailingArgs is present and trailing is true
trailingArgs = null; //reset last arguments
timer = null; // reset timer
}, delay);
}
}
13. Basic Throttle()
Function:
throttle(func, delay)
Description: Runs a given function just once in a given period
Polyfill JS, HTML, Usecase result: Throttle
/**
* @param {Function} customBasicThrottle
* @param {Function} func
* @param {number} millisec delay
*/
//What are we doing here?
//1. Set the context and trailing arguments
//2. If not executed before, execute now and update the context
//3. during exe, update the context and if trailing args exist, execute the function
//and reset the context and last args
//4. If executed, save the context for later execution
function customBasicThrottle(func, delay) {
let lastRan = false, //last time the function got ex ecuted
trailingArgs = null; //last arguments
return function (...args) { //returns function
if (!lastRan) { //if the function didnt get executed before
func.apply(this, args) // call the function
lastRan = true; //update the flag
let timer = () => setTimeout(() => { //while executing
lastRan = false; //update the flag
if (trailingArgs) { // if last arguments exist
func.apply(this, trailingArgs); //invoke the function with those last arguments
lastRan = true; //update the flag
trailingArgs = null; //reset the arguments
timer();
}
}, delay);
timer();
}
else // if function got executed before
trailingArgs = args //else update the last arguments with passed arguments
}
}
12. Throttle with leading and trailing options
Function:
throttle(callback, delay, option={leading:false, trailing: true})
Description: leading/trailing indicates function should be run at the beginning of the stream of events or the end.
Polyfill JS, HTML, Usecase result:Throttle with leading and trailing
/**
* @param {Function} func
* @param {number} delay
* @param {boolean} option.leading
* @param {boolean} option.trailing
*/
//What are we doing here?
//1. Set the context, timer and trailing arguments
//2. if timer called within cooldown period, update context and save the trailing args for later execution
//3. If leading, execute the function
//4. If trailing, update context and save last args for later execution
//5. set cooldown period
//6. if trailing and the trailing args exist, invoke the timer, reset the cooldown period
const advThrottle = (func, delay, options = { leading: true, trailing: false }) => {
let timer = null,
lastRan = null,
trailingArgs = null;
return function (...args) {
if (timer) { //called within cooldown period
lastRan = this; //update context
trailingArgs = args; //save for later
return;
}
if (options.leading) {// if leading
func.call(this, ...args) //call the 1st instance
} else { // else it's trailing
lastRan = this; //update context
trailingArgs = args; //save for later
}
const coolDownPeriodComplete = () => {
if (options.trailing && trailingArgs) { // if trailing and the trailing args exist
func.call(lastRan, ...trailingArgs); //invoke the instance with stored context "lastRan"
lastRan = null; //reset the status of lastRan
trailingArgs = null; //reset trailing arguments
timer = setTimeout(coolDownPeriodComplete, delay) //clear the timout
} else {
timer = null; // reset timer
}
}
timer = setTimeout(coolDownPeriodComplete, delay);
}
}
Find more polyfills @ Github: JS Polyfills
Keep Learning!