If you are familiar with the concept of asynchronous programming, you must have come across scenarios where you need to loop over asynchronous calls. For example, you need to get email ids of all users related to a project with ID Proj_ID for sending a report.

user1 --> email1
user2 --> email2
       .
       .
useri --> emaili

Now, considering all your users are stored in a database and getting email Ids of all the users related to Proj_ID will be an asynchronous call to the database. You need to ensure email Ids of all users have been fetched before initiating mail sending. One of the best ways of doing this is via a node module called async:

Using Async Library

For using Async module:

npm install async --save

This will add async to your node modules. Now, you can include it in the file you wish to use as:

var async = require('async');

Once, you have all the users, you can find their IDs and create an array of emails which can be used by you mailService for sending the report. Here is a snippet for the same:

    var emails = [];
    async.each(userIDs, function(userID, callback) {
        UserService.getUserFromID(userID, function(err, user) {
          if (err || !user) { 
            console.log(err);
            // Even in case of error, don't forget to call the callback
            callback();
          } else {
            email.push(user.email);
            callback();
          }
        }) }, 
        function(err) {
          if (err) {
            console.log(err);
          } else { 
            MailService.sendReportEmail(emails);
          }
      });
    }
});

In the snippet above, async.each will take an array of userIDs and initiate asynchronous calls for all userIDs. Once the DB call for a user is finished, it will call callback function which ensures that async has completed action for that particular user. Once, callback is called for all the users, and there has been no error, it will call the final callback which in our case callsMailService.sendReportEmail on the email array. You need to remember to call a callback() in error function as well else async would not be able to exit and will be stuck waiting for all DB calls to be finished.

Also, if you call callback with error like callback(error) it will pass that error to the final callback. Depending on the severity of the error you can go ahead or abort the operation you want to do in the final callback.

Async foreach

This is what is happening visually here, each callback is called in parallel here, and each may finish at different times, however, the final callback will only be called when all the callbacks are finished.

You can read about Async in details here.