Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nodejs async series - pass arguments to next callback

Tags:

node.js

When you use async module, how can you then pass arguments from the previous callback to the next?

Here is an example from the docs on github

async.series({
    one: function(callback){
        setTimeout(function(){
            callback(null, 1);
        }, 200);
    },
    two: function(callback){
        setTimeout(function(){
            callback(null, 2);
        }, 100);
    }
},
function(err, results) {
    // results is now equal to: {one: 1, two: 2}
});
like image 830
clarkk Avatar asked Mar 15 '14 13:03

clarkk


People also ask

Can we use async in callback?

Asynchronous callbacks are functions passed to another function that starts executing code in the background. Typically, when the code in the background finishes, the async callback function is called as a way of notifying and passing on data to the callback function that the background task is finished.

How do you use async parallel?

The first argument to async. parallel() is a collection of the asynchronous functions to run (an array, object or other iterable). Each function is passed a callback(err, result) which it must call on completion with an error err (which can be null ) and an optional results value. The optional second argument to async.

How do I use async series?

Async. series takes the collection of asynchronous functions and optional callback method. When all the tasks complete the execution, then the final callback will be called and return the results to the server. This result variable will hold the array of the item with the company, job, application, and licence object.

How many callback functions can be executed at any time?

As long as the callback code is purely sync than no two functions can execute parallel.


3 Answers

You can chain together asynchronous functions with the async module's waterfall function. This allows you to say, "first do x, then pass the results to function y, and pass the results of that to z." Copied from the [docs][1]:

async.waterfall([
    function(callback){
        callback(null, 'one', 'two');
    },
    function(arg1, arg2, callback){
        // arg1 now equals 'one' and arg2 now equals 'two'
        callback(null, 'three');
    },
    function(arg1, callback){
        // arg1 now equals 'three'
        callback(null, 'done');
    }
], function (err, result) {
   // result now equals 'done'    
});

You don't strictly need the async module to accomplish this; this function is designed to make the code easier to read. If you don't want to use the async module, you can always just use traditional callbacks.

like image 57
AlexMA Avatar answered Oct 11 '22 04:10

AlexMA


Another option is to use async.auto. With async auto you can specify the dependency data for a task and async will begin to run it when able to. There is a good example in the README.md, but here is roughly your series from above:

async.auto({
    one: function(callback){
        setTimeout(function(){
            callback(null, 1);
        }, 200);
    }, 
    // If two does not depend on one, then you can remove the 'one' string
    //   from the array and they will run asynchronously (good for "parallel" IO tasks)
    two: ['one', function(callback, results){
        setTimeout(function(){
            callback(null, 2);
        }, 100);
    }],
    // Final depends on both 'one' and 'two' being completed and their results
    final: ['one', 'two',function(err, results) {
    // results is now equal to: {one: 1, two: 2}
    }];
});
like image 27
Mike Graf Avatar answered Oct 11 '22 04:10

Mike Graf


I spent quite a bit of time solving this issue because I encountered similar situation. I tried both async.series and async.waterfall.

async.series: Used a variable to share across the callback functions. I am not sure whether this is the best way to do it. I must give credit to Sebastian for his wonderful article about async.

var async1 = require('async');

exports.asyncSeries1 = function (req, res, callback) {

    var sharedData = "Data from : ";
    async1.series([
            // First function
            function(callback) {
                sharedData = "First Callback";
                callback();
            },
            // Second function
            function(callback){
                console.log(sharedData);
                sharedData = "Second Callback";
                callback();
            }
        ],
        // Final callback 
        function(err) {
            console.log(sharedData);
            if (err) {
                callback();
            }
            callback();
        }
    );
};

async.waterfall: I tried using another callback function using async.apply. Here is the piece of code that helped me solve the problem. `

var async2 = require('async')

exports.asyncWaterfall1 = function (arg1, arg2, cb) {
    async2.waterfall([
        // async.apply
        async2.apply(assignVariables, arg1, arg2),
        // First callback
        function(arg1, arg2, callback){
            console.log(arg1);
            console.log(arg2);
            arg1 = 5;
            arg2 = 6;
            callback(null, arg1, arg2);
        },
        // Second callback
        function(arg1, arg2, callback){
          // arg1 now equals 'one' and arg2 now equals 'two'
            console.log(arg1);
            console.log(arg2);
            arg1 = 7;
            arg2 = 8;
            callback(null, arg1, arg2);
        }
    ], 
    function (err, arg1, arg2) {
        console.log(arg1);
        console.log(arg2);  
    });
};

// Method to assign variables
function assignVariables(arg1, arg2, callback) {
    console.log(arg1);
    console.log(arg2);
    arg1 = 3;
    arg2 = 4;
    callback(null, arg1, arg2);
};

PS: Credit.

like image 9
user1744917 Avatar answered Oct 11 '22 05:10

user1744917