Picture of the author

Amit Khonde

JavaScript Interviews: Write a custom debounce function

Debouncing function calls is one of the most widely used concepts on web pages today. Every popular JavaScript helper library like Lodash and Underscore provides a debounce function. The most popular example of debouncing is the amazon search functionality. This makes debouncing a hot topic for an interview and hence I was asked to write a custom debounce function in my recent interview.

If you folks the simplest explanation on what debounce is, you can refer to this simplest explaination on debounce and throttle.

Question

Write a custom debounce function that will take a function fn and time period t (milliseconds) as parameters. The function will return the debounced version of fn

Example Usage

1 2 3 4 5 6 7 8 9 function clickHandler() { // An expensive API call } function debounce(fn, t) { // Write your code here } const debouncedClickHandler = debounce(clickHandler, 300);

Note: Before diving into the solution, try to solve this problem on your own. Here is a hint: Think closures and setTimeout.

Answer

When I am solving any problem, I always like to write the obvious things first. Those things can be found by reading the problem statement carefully. There are 3 very obvious things in this question:

  • Our custom debounce function is going to return a function.
  • That returned function is going to execute the fn we received in the parameters.
  • fn is going to be called after time t . This we can achieve using setTimeout.

Let us start with writing code for these 3 things first

1 2 3 4 5 6 7 function debounce(fn, t) { return function() { setTimeout(() => { fn(); }, t) } }

When the first call is made to our debounced function, we create a timer and execute fn at the end of it. But if another call is made to our function while the timer is going on, we want to cancel the current timer and start a new timer. To achieve this, we can capture the timer id returned by the setTimeout and use it to cancel the timer.

But if we declare the timer id within our returned function, a new value will be assigned to it and we will lose the previous timer id. This is where the concept of closures comes in.

We can declare the timer id in debounce function and access it inside our returned function. Whenever our returned function is called, we will cancel the previous timer using clearTimeout and start a new one.

Also, if any parameters are passed to our debounced function, we have to pass to fn while execution.

So the final version of our debounce function will look like this:

1 2 3 4 5 6 7 8 9 function debounce(fn, t) { var timerId; return function(...args) { clearTimeout(timerId) timerId = setTimeout(() => { fn(...args); }, t); } }

Conclusion

Yay!! This looks like a working solution now. But there are still minor problems with this solution like handling the context of the function. I encourage you to write the code that will handle this condition. And for more interesting questions like this, keep following this series. Until then, Happy Coding!!

Share

Share on twitter
Share on facebook

Like what you are reading? Subscribe for new posts every week