21/08/2024

[TypeScript] Debounce function in vanilla TypeScript

Debouncing is a technique to execute a function only once during a configured period while specific trigger conditions are true. This can be used to improve performance and user experience.

The idea is to track the last time the desired function was invoked, and update such timer on each subsequent invocation, resetting the timer to the new time. If no other call is made within the configured delay after the last time of invocation, the function will finally be triggered at the end of the period.
Here is a sample generic debounce function that will accept any number or arguments and has no return value, it could be easily changed to produce an output as well instead. It will return a debounced version of the function received in input, maintaining same signature.

function debounce<T extends (...args: any[]) => void>(func: T, delay: number): (...args: Parameters<T>) => void {
    let timeout: ReturnType<typeof setTimeout>;

    return function(this: ThisParameterType<T>, ...args: Parameters<T>): void {
        if ( timeout !== null) {
            clearTimeout(timeout);
        }

        timeout = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    };
}

To be independent from the framework we are using, we detect the timer type (since TypeScript does not have one) returned by the setTimeout function, wherever that is implemented.

This specific implementation will delay every execution, including the first invocation. If you prefer to have the first call trigger immediately, you can modify the code in the null check.

There is no way with this implementation to cancel the execution of the debounced function before it is scheduled to be invoked, should you require this, you might want to modify the provided code.

We can now pass any function to the debounce function to create a debounced version of it:

function foo(){
  console.log("Hello world");
}

const debouncedFoo = debounce(foo, 1000);

debouncedFoo();

Executing this code sample, will trigger the function when run, but execute the function foo only after the configured delay of 1 second has passed. If we link debouncedFoo to a trigger event (scroll, type in a text field, press a button, etc), and we fire the trigger event multiple times within 1 second, we will see that foo will only be executed after 1 second from the last trigger time, as expected.

No comments:

Post a Comment

With great power comes great responsibility