Skip to main content

debounceCancelFlush

/**
* @typedef {((...args: Array<unknown>) => void) & {
* cancel: () => void,
* flush: () => void,
* }} DebouncedFunction
*/

/**
* @param {Function} func
* @param {number} [wait=0]
* @return {DebouncedFunction}
*/
export default function debounce(func, wait) {
let timeout;
let lastArgs;
let lastThis;
function debounced(...args) {
lastArgs = args;
lastThis = this;
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(lastThis, lastArgs);
timeout = null;
lastArgs = null;
lastThis = null;
}, wait);
}
debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
lastArgs = null;
lastThis = null;
}
debounced.flush = function() {
if (timeout == null) {
return;
}
clearTimeout(timeout);
const result = func.apply(lastThis, lastArgs);
timeout = null;
lastArgs = null;
lastThis = null;
return result;
}
return debounced;
}

// Debouncing is a technique used to control how many times we allow a function to be executed over time. When a JavaScript function is debounced with a wait time of X milliseconds, it must wait until after X milliseconds have elapsed since the debounced function was last called.

// You almost certainly have encountered debouncing in your daily lives before (e.g. when entering an elevator). Only after X duration of not pressing the "Door open" button (the debounced function not being called) will the elevator door actually close (the callback function is executed).

// Implement a debounce function which accepts a callback function and a wait duration. Calling debounce() returns a function which has debounced invocations of the callback function following the behavior described above.

// Additionally, the debounced function comes with two extra methods:

// cancel() method to cancel pending invocations
// flush() method to immediately invoke any delayed invocations

```
let i = 0;
function increment() {
i++;
}
const debouncedIncrement = debounce(increment, 100);

// t = 0: Call debouncedIncrement().
debouncedIncrement(); // i = 0

// t = 50: i is still 0 because 100ms have not passed.
// t = 51:
debouncedIncrement.flush(); // i is now 1 because flush causes() the callback to be immediately invoked.

// t = 100: i is already 1. The callback has been called before
// and won't be called again.
```