Borrowing a JavaScript Debounce
Tags: javascript, webdev, beginners
Published: 2020-12-06 20:30:20

Sometimes, we end up doing heavy things like running functions whenever a user scrolls a web page. The problem arises not from the block of code we're trying to run, but from running it too many times in too short a timeframe. Again, scrolling is a good example of this kind of situation, because if a user scrolls the page from bottom to top they'll trigger the event listener many times in just a second or two.

Situations like this where we need to optimize our JavaScript might benefit from a **debounce** function. We can use a debounce function like the once below, adapted from [Underscore.js](https://underscorejs.org/), to **limit how often a block of code is run**. 

More specifically--we pass a function (the block of code we want to run) and a number of milliseconds to our debounce. Our debounce then ensures that instead of calling that function immediately on time, it only calls the function once the call has ceased for our specified number of milliseconds. This is not the same as **throttling**, though the results can be similar.

Hold onto this debounce implementation:

```javascript
var debounce = (func, wait, immediate) => {
    return function() {
      var context = this;
      var later = function() {
        var args = arguments;
        if (!immediate) {
          func.apply(context, args);
        }
      }
    }
  }
```

Using it is simple. Let's continue along with our scrolling example. Imagine we have a function called `logScroll()` that we want to trigger when the user scrolls our page. We can use `debounce()` while setting that event listener to ensure our function only triggers once, half a second after scrolling ceases. So we pass two arguments to `debounce()`: the function we want to debounce, and the length of time in milliseconds to wait.

```javascript
// Code we want to trigger on scroll
function logScroll() {
  console.log('scroll');
}

// Set up the event listener using debounce
document.addEventListener('scroll', debounce(logScroll, 500));
```

Using `debounce()` in our triggering of `logScroll()` improves performance because we only call `logScroll()` once per scroll action, instead of calling it constantly during every moment of scrolling.

You may have noticed that this debounce method also takes a third argument, called `immediate`. Since in our example we didn't pass in a third argument, `immediate` is undefined, however we can pass a `true` value into `immediate` and force `logScroll()` to trigger when scrolling begins rather than ends. The 500 millisecond wait before `logScroll()` can be called again still occurs and improves page performance.

```javascript
// Set immediate argument to true to trigger function first
document.addEventListener('scroll', debounce(logScroll, 500, true));
```

Like much of the techniques outlined in this series, this debounce approach is a single tool for you to keep on hand and employ when needed. Sometimes, your purposes might be better served by a throttle approach rather than debounce, and sometimes more thoughtful optimizations will be needed to boost performance of your creations. Try it out and see where it works best!