DEV Community

Cover image for JS Polyfills - Part 4 Debounce & Throttle - Leading & Trailing options
Sriya
Sriya

Posted on • Edited on

JS Polyfills - Part 4 Debounce & Throttle - Leading & Trailing options


Github Code: JS Polyfills
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()

/** * @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); }); } 
Enter fullscreen mode Exit fullscreen mode

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); } } 
Enter fullscreen mode Exit fullscreen mode

13. Basic 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 } } 
Enter fullscreen mode Exit fullscreen mode

14. 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); } } 
Enter fullscreen mode Exit fullscreen mode

Keep Learning!

Top comments (2)

Collapse
 
bcdbuddy profile image
Babacar Cisse DIA

Bro your code is wrong. Spent the last 20min troubleshooting it. Below what is working for me for anyone passing

function customBasicDebounce(func, delay = 400) { let timer; return ((...args) => { clearTimeout(timer); // args is already an array no need to thread it timer = setTimeout(() => func.apply(this, args), delay); }); } 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
uttarasriya profile image
Sriya

Thank you!!