Back to the lesson

Debounce decorator

importance: 5

The result of debounce(f, ms) decorator should be a wrapper that passes the call to f at maximum once per ms milliseconds.

In other words, when we call a “debounced” function, it guarantees that all other future in the closest ms milliseconds will be ignored.

For instance:

let f = debounce(alert, 1000);

f(1); // runs immediately
f(2); // ignored

setTimeout( () => f(3), 100); // ignored ( only 100 ms passed )
setTimeout( () => f(4), 1100); // runs
setTimeout( () => f(5), 1500); // ignored (less than 1000 ms from the last run)

In practice debounce is useful for functions that retrieve/update something when we know that nothing new can be done in such a short period of time, so it’s better not to waste resources.

Open the sandbox with tests.

function debounce(f, ms) {

  let isCooldown = false;

  return function() {
    if (isCooldown) return;

    f.apply(this, arguments);

    isCooldown = true;

    setTimeout(() => isCooldown = false, ms);


The call to debounce returns a wrapper. There may be two states:

  • isCooldown = false – ready to run.
  • isCooldown = true – waiting for the timeout.

In the first call isCooldown is falsy, so the call proceeds, and the state changes to true.

While isCooldown is true, all other calls are ignored.

Then setTimeout reverts it to false after the given delay.

Open the solution with tests in the sandbox.