How to handle a duplicate function call from the arrays of function?

Your function chaining depends on the call to k(). Therefore in your cache logic:

if (cache[f]) {
    return;
} else {
    // ...

The chain breaks.

What you want instead is this:

if (cache[f]) {
    return k();
} else {
    // ...

Alternative Implementation

One of the problems with the nested function implementation is that it is hard to reason about due to multiple nesting scopes (and multiple functions being juggled at once (r, f, k, cb).

A simpler approach to this is rather than trying to programmatically build callback hell you can use a queue instead (which is what async.js does). The idea is simple, pop() or shift() functions from an array until the array is empty:

function runCallbacksInSequence(fns, cb) {
    let result = [];
    let cache = {};

    function loop () {
        if (fns.length > 0) {
            let f = fns.shift(); // remove one function from array

            if (cache[f]) {
                loop(); // skip this round
                return;
            }

            cache[f] = f;
            f(function(err, val) {
                if (!err) {
                    result.push(val); // collect result
                    loop();
                }
                else {
                    // Handle errors however you want.
                    // Here I'm just terminating the sequence:
                    cb(err, result);
                }
            });
        }
        else {
            cb(null, result); // we've collected all the results!!
        }
    }

    loop(); // start the loop
}

As you can see, it's fairly easy to implement any flow logic with this structure. We can easily implement things like waterfall, parallelLimit etc. by controlling how we keep track of results and how many functions we remove from the array per iteration.

Tags:

Javascript