Difference between debouncing and throttling

Published on

Debounce and throttle are two common techniques to rate limit something. I see debounce very often in FE apps. For example, if you run some validation code on every keydown event for a text input, it often makes more sense to debounce it so it runs at the 'end' of all typing (and only once) instead of for each key press.

Table of Contents

What is debounce

Debounce is a way to execute some code only once, even if lots of event triggers are fired at around the same time.

e.g. if i have a function like this:

/*
<html><input id="id1"/></html>
 */

const someInputField = document.getElementById('id1');

function isValidString(s) {
    return s.length > 5
}

function validateInput() {
    if(!isValidString(someInputField.value)) {
        // this is a very bad practive, just for illustration...
        alert('you have an error!')
    }
}

someInputField.addEventListener('keydown', validateInput)

then it could trigger an alert on every keydown.

But lets wrap it in debounce, and it will get triggered after the user stops firing lots of keydown events.

It is very simple to do:

  • Create a function called debounce that takes a fn argument (to be called later), and a min delay
  • get a timeoutId variable (initially undefined)
  • then return a function in that function that:
    • clears any existing timeout for this debounced function
    • then add a setTimeout() to run the fn() after a delay.
    • If the debounced function is called again, it resets the timer.

function debounce(fn, delayInMs = 100) {
  let timeoutId;
  return function() {
    clearTimeout(timeoutId);
    
    timeoutId = setTimeout(() => {
      fn()
    }, delayInMs);
  }
}

const debouncedValidateInput = debounce(validateInput, 100);

// someInputField.removeEventListener('keydown', validateInput)
someInputField.addEventListener('keydown', debouncedValidateInput)


This will make it feel more natural and more usable than seeing tons of alert()s.

How to easily use debounce

I'd recommend lodash...

import {debounce} from 'lodash';
const debouncedFunction = debounce(myFunction, 250);

What is throttle

Throttling is a technique to ensure some code immediately, but then won't allow it to be run again until a period of time.

Example of throttle:

function throttle (fn, delayInMs) {
    let canRunNow = true;
    return () => {
        if (canRunNow) {
            fn()
            canRunNow = false;
            setTimeout(() => {
                canRunNow = true;
            }, delayInMs);
        }
    }
}

Now it will run immediately, but then not again until delayInMs...

What is the difference between debounce and throttle?

  • Debounce to delay the first run until X time has passed and no other calls to run it
  • Throttle to run immediately, then don't run again until X time has passed