循环中的节点和异步调用


Node and asynchronous call inside a loop

我在将PHP同步代码翻译到Node时遇到了一个小问题。

PHP

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

我试着用这种方式转换:

节点

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);
});

但是使用此代码showView在getCode调用完成之前运行。

做这件事的正确方法是什么?如有任何帮助,将不胜感激

更新我看到这个问题被标记为重复。建议的副本在这里然而,提出的问题并不能解决我的问题。我需要在循环完成后以及循环内的所有异步调用完成后执行一个函数(showView)。

我从数据库上的Select开始,对于结果的每个元素,我需要执行另外两个查询。只有在查询完成后,我才需要执行我的功能,但我不明白如何执行,而且建议的问题并不能解决我的需求。

根据建议,我的问题的解决方案是通过AsyncRsvp库获得的。

以下是两种可能的解决方案:

ASYNC

使用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

使用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;
  });
});