async.series + for loop

1,946 views
Skip to first unread message

gonzalo...@itecnis.com

unread,
May 7, 2014, 2:13:54 PM5/7/14
to nod...@googlegroups.com
Hello guys.. I am trying to figure out how to use async.

I am runing this example :

var async = require('async');
  
for (var i = 0; i < 3; i++) {
   async.series([
          function(callback){
                 console.log("wait 4 seconds and give error if i = 2, value of i :"+ i);
                 setTimeout(function () {
                     console.log("value of i inside: "+i);
                     if(i==2)
                         callback("Error", "one");
                     else
                         callback(null, 'one');
                }, 4000);
         },
           function(callback){
              callback(null, 'two');
          }
  ],
// optional callback
      function(err, results){
          if(err) console.log("Err: " + err);
          else console.log("Finish series");
     });
};

I hope my output to be other. But i got this one:

wait 4 seconds and give error if i = 2, value of i  :0
wait 4 seconds and give error if i = 2, value of i :1
wait 4 seconds and give error if i = 2, value of i :2
value of i inside: 3
Finish series
value of i inside: 3
Finish series
value of i inside: 3
Finish series


In summary I need to make a serie of executions, n times. And in each time, I will have some parameters changing with each loop (in this example it's value of i).

Francesco Mari

unread,
May 7, 2014, 4:31:52 PM5/7/14
to nod...@googlegroups.com
async.series() executes some asynchronous functions one after the
other, in the same order as specified by the array. If you want to
repeat the same asynchronous function multiple times, you can choose
between async.times() and async.timesSeries().
> --
> Job board: http://jobs.nodejs.org/
> New group rules:
> https://gist.github.com/othiym23/9886289#file-moderation-policy-md
> Old group rules:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> ---
> You received this message because you are subscribed to the Google Groups
> "nodejs" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to nodejs+un...@googlegroups.com.
> To post to this group, send email to nod...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/nodejs/57fd29cf-0a34-4469-94fc-a54be8eaf0cb%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Kushal Likhi

unread,
May 7, 2014, 11:58:22 PM5/7/14
to nod...@googlegroups.com

Hi,

Well the key is that we much accumulate the tasks first using loops or other mechanisms, and then run the async.series control flow in the end and only once.

To convert your example to a working solution, i will guide via 2 steps:

Refactor 1: Task accumulation (Will not work as expected though)

Here lets first change the program to a async friendly design.

var async = require('async');

//Tasks Array
var tasks = [];

for (var i = 0; i < 3
; i++) {
    //Push your first looped task
    tasks.push(function (callback) {

            console.log("wait 4 seconds and give error if i = 2, value of i :" + i);
            setTimeout(function () {
                console.log("value of i inside: " + i);
                if (i == 2)
                    callback("Error", "one");
                else
                    callback(null, 'one');
            }, 4000
);
        });

    //Second task pushed
    tasks.push(function (callback) {
            callback(null, 'two From ' + i);
        });
};

//Run the control flow
async.series(tasks, function (err, results) {
    if (err) console.log("Err: ", err, "\nResults:", results);
    else console.log("Finish series.", results);
});

HURRAY!! This is done and correct way. BUT the issue above will be that when each task function runs the value of i will be 4 because the scope was still lexical and the final value of i was considered. This problem would not be there if any enclosed scope variables were used, or forEach etc.. were used.

Refactor 2: Fixed Scope issue

Lets now create closures for task functions such that it works. This is a simple solution and easy one, there are better ways to do it which require a slight design change. But lets stick to the simple one.

var async = require('async');

var tasks = [];

for (var i = 0; i < 3
; i++) {

    /* NOW as you are using the for loop with changing value of i, 
     * hence you need to create a closure to encapsulate the snapshot of scope at time of creation.
     * 
     * Note: If any enclosed scope was used, like in forEach loop then the outer wrapping function was not required.
     */

    //Making closure 
    tasks.push((function (i) {
        //We are returning the actual task function here with enclosed scope containing 'i'
        return function (callback) {

            console.log("wait 4 seconds and give error if i = 2, value of i :" + i);
            setTimeout(function () {
                console.log("value of i inside: " + i);
                if (i == 2)
                    callback("Error", "one");
                else
                    callback(null, 'one');
            }, 4000
);
        };
    })(i));

    //Second task closure
    tasks.push((function (i) {
        return function (callback) {
            callback(null, 'two From ' + i);
        };
    })(i));
};

async.series(tasks, function (err, results) {
    if (err) console.log("Err: ", err, "\nResults:", results);
    else console.log("Finish series.", results);
});

Victory! Here everything will fork fine as expected. :)

Output:

wait 4 seconds and give error if i = 2, value of i :0
value of i inside: 0
wait 4 seconds and give error if i = 2, value of i :1
value of i inside: 1
wait 4 seconds and give error if i = 2, value of i :2
value of i inside: 2
Err:  Error 
Results: [ 'one', 'two From 0', 'one', 'two From 1', 'one' ]

See it running live

live example hosted here: http://www.node-console.com/script/async-usage-example
Note: execution takes time due to 4 second timeouts

Regards



--
Job board: http://jobs.nodejs.org/
New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
---
You received this message because you are subscribed to the Google Groups "nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+un...@googlegroups.com.
To post to this group, send email to nod...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/57fd29cf-0a34-4469-94fc-a54be8eaf0cb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

KUSHAL LIKHI

Vertical Head Node.JS

T : +91 1206493668                                 M : +91 9873333033

E : kus...@intelligrape.com                   W : www.intelligrape.com

Description: Description: Intelligrape_Signature Temp

Twitter: KushalLikhi | LinkedIn: Kushal Likhi | FB: kushal.likhi | Skype: kushal.likhi  

Dan Schmidt

unread,
May 8, 2014, 2:53:58 AM5/8/14
to nod...@googlegroups.com
I've actually just started learning to use Async as well.

Firstly, if you have a bit a time to spare, I recommend the nodeschool.io workshop "async-you". I just ran through it yesterday and it's a pretty good introduction to the module.

I was playing around with your example some, here's a version using series and timesSeries like Francesco recommends: https://gist.github.com/DanSchmidt/0f76d6eac31b538fe0df
Reply all
Reply to author
Forward
0 new messages