Function debounce

Source
debounce<TFn extends AnyFn>(
    args: DebounceConstructor<TFn>,
): (...args: Parameters<TFn>) => Promise<AwaitRet<TFn>>

An async event wrapper to execute a function with a minimal interval between calls.

The implementation is guaranteed to:

  • Not re-fire in a minimal interval after it's initialially fired.
  • All calls will eventually fire

The caller will get a promise that resolves the next time the event is fired and resolved.

Unlike the naive implementation with a setTimeout, this implementation will not starve the event. If it's constantly being called, it will keep firing the event at at least the minimum interval (might take longer if the underlying function takes longer to execute

Multiple calls will be debounced to the minimum interval

import { debounce } from "@pistonite/pure/sync";

const execute = debounce({
fn: () => {
console.log("called");
}
interval: 100,
});
await execute(); // resolved immediately
await execute(); // resolved after 100ms

When making multiple calls, if the call is currently being debounced (i.e. executed and the minimum interval hasn't passed), new calls will replace the previous call.

If you want to the in-between calls to be preserved, use batch instead.

import { debounce } from "@pistonite/pure/sync";

const execute = debounce({
fn: (n: number) => {
console.log(n);
}
interval: 100,
});
await execute(1); // logs 1 immediately
const p1 = execute(2); // will be resolved at 100ms
await new Promise((resolve) => setTimeout(resolve, 50));
await Promise.all[p1, execute(3)]; // will be resolved at 100ms, discarding the 2nd call
// 1, 3 will be logged

By default, the debouncer takes into account the time it takes for the underlying function to execute. It starts the next cycle as soon as both the minimul interval has passed and the function has finished executing. This ensures only 1 call is being executed at a time.

However, if you want the debouncer to always debounce at the set interval, regardless of if the previous call has finished, set disregardExecutionTime to true.

import { debounce } from "@pistonite/pure/sync";

const execute = debounce({
fn: async (n: number) => {
await new Promise((resolve) => setTimeout(resolve, 150));
console.log(n);
},
interval: 100,
// without this, will debounce at the interval of 150ms
disregardExecutionTime: true,
});

See DebounceConstructor for options