Timed version for async waterfall

106 views Asked by At

I want to override async.waterfall() (or write timed_waterfall()) so that it prints execution time for each step. How to do that?

async.waterfall([
    f=>{
        console.log('step1');
        f();
    },
    f=>{
        console.log('step2');
        f();
    },
    f=>{
        console.log('step3');
        f();
    },
],
()=>{
    console.log('done');
})

Desired output:

step1
1ms
step2
2ms
step3
1ms
done
5ms
3

There are 3 answers

0
exebook On

Compatible with async.js waterfall():

function timed_waterfall(tasks, ender) {
    function color(a) {
        if (a == undefined) { return '\u001b(B\u001b[m' }  
        return '\u001b[38;5;'+a+'m'
    }

    var N = 0;

    function go(args) {
        function f() {
            if (N>0)console.timeEnd(color(1)+' * '+N+color())
            var res = Array.prototype.slice.apply(arguments);
            if (res[0]) {
                ender.apply(null, res);
            }
            else {
                res.splice(0, 1);
                var cb = tasks.shift();
                if (cb) {
                    res.push(f);
                    console.time(color(1)+' * '+(++N)+color())
                    cb.apply(null, res);
                }
                else {
                    res.unshift(null)
                    ender.apply(null, res);
                }
            }
        }
        f(null);
    }
    go([]);
}

It's easy t modify to print the totals as well.

0
Bergi On

You don't need to modify waterfall at all - simply write a wrapper function that adds the timing to a task (callback-taking function):

function withTiming(fn, name) {
    if (typeof name == "number") name = "step"+name;
    return function() {
        var start = Date.now()
        var lastIndex = arguments.length-1;
        var cb = arguments[lastIndex];
        arguments[lastIndex] = function() {
            console.log(name+": "+(start-Date.now())+"ms");
            cb.apply(this, arguments);
        };
        return fn.apply(this, arguments);
    };
}

You can use it together with async.js like this:

async.waterfall([
    f=>{
        console.log('step1');
        f();
    },
    f=>{
        console.log('step2');
        f();
    },
    f=>{
        console.log('step3');
        f();
    },
].map(withTiming), ()=>{
//^^^^^^^^^^^^^^^
    console.log('done');
})
0
Afanasii Kurakin On

How about this?

function timedWaterfall (tasks, callback) {
  console.time('total')
  async.waterfall(tasks.map(function (task, i) {
    return function () {
      if (i > 0)
        console.timeEnd('step' + i)
       console.time('step' + (i + 1))
       return task.apply(null, arguments)
    }
  }),
  function () {
    console.timeEnd('total')
    callback.apply(null, arguments)
  })
}