# Source: Debounce.ts

    const timeoutIds: Record<string | number, NodeJS.Timeout> = {};

    export function updateMakeupDebounce(
        id: number,
        fn: CallableFunction,
        delay: number,
        args: unknown[],
    ) {
        const timeoutId = timeoutIds[id];
        if (timeoutId) clearTimeout(timeoutId);
        timeoutIds[id] = setTimeout(() => {
            delete timeoutIds[id];
            fn(...args);
        }, delay);
    }

    /**
     *
     * @param id effect.id or productUsagePattern.id, it's a mix of domains for this function.
     * As things stand, it makes no sense to have both codepaths (MakeupEngine and CMSMakeupEngine) used at the same time.
     * So problems/clashes should not occur, but this is still semantically unsound
     * @param fn action to invoke
     * @param delay in ms
     */
    export function updateMakeupDebounce2(
        id: number,
        fn: VoidFunction,
        delay: number,
    ) {
        const timeoutId = timeoutIds[id];
        if (timeoutId) clearTimeout(timeoutId);
        timeoutIds[id] = setTimeout(() => {
            delete timeoutIds[id];
            fn();
        }, delay);
    }