Node and asynchronous call inside a loop

i have a little problem whit translation of a PHP sync code to Node.

PHP

$bodies = getBodystyles();
foreach($bodies as $b) {
  $aCar['body'] = $b['Body'];
  $code = getCode($aCar);
  $promo = checkPromotionByCarID($code['Car']);
}

i'll try to convert it in this way:

NODE

db.getBodystyles(function(err, bodies){
  for (b in bodies) {
    console.log(bodies[b]);
    var aCar = Common.ConfiguratorDefault;
    db.getCode(aCar, function(err, code){
      console.log(code);
      bodies[b].aCar = aCar;
      bodies[b].code = code;
      // checkPromotionByCarID here?
    });
  }
  options.bodies = bodies;
  showView(options);
});

but with this code showView run before getCode calling finish.

what the right approach to do that? any help would be appreciated

UPDATE I see this question is marked as duplicated. The suggested duplicate are here However the question proposed doesn't solve my problem. I need to perform a function (showView) after loop finish and after all asynchronous calls inside the loop are finished.

i start from a Select on DB and for each element of result i need to perform other two queries. Only after that queries are finished i need to perform my function and i doesn't understand how do that, and the question suggested doesn't solve my need.

as suggested, the solution to my problem is obtained with the libraries Async or Rsvp.

Below are two possible solutions:

ASYNC

Using Async.js

db.getBodystyles(function(err, bodies){
    async.each(bodies, function( b, callback) {
        var aCar = Common.ConfiguratorDefault;
        aCar.body = b.Body;
        db.getCode(aCar, function(err, code){
            if (err){
                callback(err);
            }else{
                b.aCar = aCar;
                b.code = code;
                db.checkPromotionByCarID(code.Car, function(err, promo){
                    if (err){
                            callback(err);
                    }else{
                            b.promo = promo;
                            callback();
                    }                           
                });
            }
        });
    },function(err){
        if( err ) {
            console.log('A file failed to process');
            res.render('500');
        } else {
            console.log('All files have been processed successfully');
            options.bodies = bodies;
            showView(options);
        }
    });
});

RSVP

Using Rsvp.js

db.getBodystyles(function(err, bodies){
  var promises = bodies.map(function(b) {
    var aCar = Common.ConfiguratorDefault;
    aCar.body = b.Body;
    var promise = new RSVP.Promise(function(resolve, reject) {
      db.getCode(aCar, function(err, code){
        if(err) reject(err);
        b.aCar = aCar;
        b.code = code;
        db.checkPromotionByCarID(code.Car, function(err, promo){
            if(err) reject(err);
            b.promo = promo;
            resolve();
        });
      });
    });
    return promise;
  };

  RSVP.all(promises).then(function() {
    options.bodies = bodies;
    showView(options);
  }).catch(function(err) {
    throw err;
  });
});