Is the debounce function idempotent?

Viewed 110

This is a standard debounced function that works well (tested...)

function debounce(func, wait = 300, delay = false) {
    
    let waitingClock;

    return function () {

        const context = this;
        const args = arguments;
        const immediateCall = !waitingClock && !delay;

        clearTimeout(waitingClock);

        waitingClock = setTimeout(function () {

            waitingClock = null;

            if(!immediateCall)
                func.apply(context, args);

        }, wait);

        if(immediateCall) 
            func.apply(context, args);

    }

}

const log = function() {
    console.count("Logging something ");
}

We generally do this:

const safeLog = debounce(log, 300, false);

and it works ... 100 %

But I have seen that if I do this,

const safeLog = debounce(debounce(log, 300, false));
const safeLog = debounce(debounce(debounce(log, 300, false)));
const safeLog = debounce(debounce(debounce(debounce(log, 300, false))));

it still works same like above. So is it safe to conclude debounce is an idempotent function ? I need some insight as to why ?

1 Answers

No.

I think you are confused about the meaning of "idempotence."

A function is idempotent if calling it multiple times has the same effect as calling it only one time.

Your function is deterministic (I believe), which is not the same thing:

let originalFunc = () => { /* stuff */ }

let fnA = debounce(originalFunc)
let fnB = debounce(originalFunc)

fnA works the same way as fnB. But that is not the same as this:

let fnA = debounce(originalFunc)
let fnB = debounce(debounce(originalFunc))

For one thing: fnB will create two timers. That might not be noticeable in your app, but if you're writing unit tests you will probably have to address that fact.

Interestingly, this debounce creates a timer even if it doesn't need one. (You should probably avoid creating the timer, or use setImmediate instead, if func should be invoked immediately.)

This debounce has side-effects that will stack if you nest calls. Those effects might not be visible in your use-case, but they are real and that seals the deal.

Related