Async: Version of async.series where each task receives the results of all previous tasks

Created on 16 Nov 2015  ·  5Comments  ·  Source: caolan/async

I frequently encounter a situation where a async.series task need the results of several previous tasks. async.waterfall is insufficient since it only provides the result of the last previous task. async,auto is too verbose, and provides additional, unneeded dependency declaration.

A new function (or an improvment of async.series) would come in handy. Each task would receive a result object containing the results of all previous tasks

Possible names: accumulate, seriesAccumulate

Example:

async.accumulate({
    one: function(callback){
        setTimeout(function(){
            callback(null, 1);
        }, 200);
    },
    two: function(callback, results){
        // results: {one: 1}
        setTimeout(function(){
            callback(null, 2);
        }, 100);
    },
    three: function(callback, results){
         // results: {one: 1, two: 2}
        setTimeout(function(){
            callback(null, results.one + results.two);
        }, 100);
    }
},
function(err, results) {
    // results is now equal to: {one: 1, two: 2, three: 3}
});
feature question

All 5 comments

Have you checked out async.auto? It does something very similar to what you describe.

As I mentioned, in a simple series scenario async.auto is too verbose, The user have to declare that each step is dependent on the previous one, resulting in those ugly arrays and duplicate step names

async.auto({
    one: function(callback){
        setTimeout(function(){
            callback(null, 1);
        }, 200);
    },
    two: ["one", function(callback, results){
        setTimeout(function(){
            callback(null, 2);
        }, 100);
    }],
    three: ["two", function(callback, results){
        setTimeout(function(){
            callback(null, results.one + results.two);
        }, 100);
    }
   ]
},
function(err, results) {
    // results is now equal to: {one: 1, two: 2, three: 3}
});

We are going to make some enhancements to auto in the next major release -- always have the callback last, and also add autoInject (#608) which infers the dependencies from the parameter names.

I don't like this proposal because it relies on the order of the object keys -- something which is not guaranteed across JS environments (and is only guaranteed in Node for small objects). With arrays it is possible, but it is too similar to async.waterfall. I'm not sure we need something in between auto and waterfall, especially if we're adding autoInject.

A way to accomplish what you want:

function seriesAccumulate(tasks, done) {
  async.reduce(tasks, [], function (results, task, next) {
    task(results, function (err, result) {
      results.push(result);
      next(err, result);
    });
  }, done);
}

I'd recommend against trying to use an object to iterate in series.

Closing this. I don't think we need another method between series and waterfall in style.

Was this page helpful?
0 / 5 - 0 ratings