Photo by Joshua Reddekopp on Unsplash

Implementing Debounce in JS

DJ Taylor
3 min readNov 22, 2021

--

Before I jump into this debounce business, let me share a few quick updates about life post-Flatiron School. Between building a portfolio site, making my LinkedIn profile nice and shiny, and tweaking my resume, there’s a lot to balance in the search for my first developer gig. With that said, what’s really giving me life right now is continuing to learn new skills and technologies. Over the last month or so, I’ve really enjoyed digging deeper into GraphQL, Apollo, urql, Node.js, and Gatsby. I also discovered a really great learning platform called Frontend Masters. They offer a ton of courses covering a wide variety of topics (React, Vue, Typescript, Angular, Data Structures, etc). Definitely check them out if you’re looking to ramp up your learning. Ok, let’s get to work with debounce.

One of the courses I’m currently working through on Frontend Masters is Javascript: The Hard Parts, v2. This course goes into a lot of detail about what is happening under the hood with Javascript, including closure, lexical scope, execution contexts, and promises/async functions. One of the challenges from the async functions section was to implement a debounce function. Here’s the problem:

Write a function called debounce that accepts a function and returns a new function that only allows invocation of the given function after interval milliseconds have passed since the last time the returned function ran.

Additional calls to the returned function within the interval time should not be invoked or queued, but the timer should still get reset.

Aside from being a common technical interview challenge, debounce functions are also utilized to improve performance in an application by preventing excessive function calls to a server or API.

Here’s my solution, which I’ll break down line by line below:

function debounce(callback, interval) {

let setTimeoutId;

return function() {

if (!setTimeoutId) {
setTimeoutId = true;
return callback();
}
setTimeoutId = setTimeout(() => {
setTimeoutId = null;
}, interval)
}
}
  • First, declare a function debounce that takes a callback function and interval (in milliseconds) as arguments
  • Declare a variable called setTimeoutId, which is initially undefined.
  • Declare the function that will be returned by debounce
  • If setTimeoutId is false (which it will be on the first invocation), setTimeoutId becomes true and the callback function is invoked.
  • If the function is called multiple times in succession, setTimeoutId will return true and hit this line which uses setTimeout. Essentially, setTimeoutId will remain true until after the interval has finished, when it will be set to null. The value of the callback function will not be returned until that point, preventing excessive calls.
  • To clarify, if the function is run within the setTimeout interval, it will return undefined and start a new timer.

Now, here are some test cases to verify that this works:

function giveHi() { return 'hi' } // -> this is the callback fnconst giveHiSometimes = debounce(giveHi, 3000);console.log(giveHiSometimes()); // -> 'hi'setTimeout(function() { console.log(giveHiSometimes()); }, 2000); // -> undefinedsetTimeout(function() { console.log(giveHiSometimes()); }, 4000); // -> undefinedsetTimeout(function() { console.log(giveHiSometimes()); }, 8000); // -> 'hi'

Since the functions with the intervals of 2000ms and 4000ms are called within the 3000ms interval initially declared, they return undefined. However, by the time 8000ms pass (the last function call), setTimeoutId is set to null and the callback is allowed to run once again.

There we have it! While there are other debounce solutions that apply in different contexts, this works well for this particular challenge. If you have feedback or suggestions, I’d love to hear what you think.

That’s all for now, folks. Thanks for stopping by!

--

--

DJ Taylor
0 Followers

Based in Los Angeles, I’m a full stack developer and recent graduate of the Flatiron School.