Javascript 节点与生成器和Promise协同执行并行流控制

Javascript 节点与生成器和Promise协同执行并行流控制,javascript,node.js,generator,bluebird,co,Javascript,Node.js,Generator,Bluebird,Co,我试图用协同程序和承诺来模拟async.js库的控制流,同时使用co和bluebird.js,但我遇到了一些问题。我的代码如下所示,虽然这大部分是伪代码,因为实际的代码会很长,如果需要的话,我可以稍后添加acutal代码 co(function*(){ var re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; var doc = yield People.findOne({email: req.body.email

我试图用协同程序和承诺来模拟async.js库的控制流,同时使用
co
bluebird.js
,但我遇到了一些问题。我的代码如下所示,虽然这大部分是伪代码,因为实际的代码会很长,如果需要的话,我可以稍后添加acutal代码

 co(function*(){  
    var re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
    var doc = yield People.findOne({email:  req.body.email}).exec();

    var filePath = path.join(__dirname, '../email-template.html');                         
    var html = yield fs.readFileAsync(filePath,'utf8');
    var emailsToSend = [];
    var emailStatuses = [];
    var validEmails = [];

    //make sure email is ok
    req.body.messagesToSend.forEach(function(message){
      if(message.email != null && re.test(message.email))
      { 
        validEmails.push(message);
      }else{
        // mark it as failed...
        emailStatuses.push({success : "FAILURE", email : message.email}); 
      }
    });

    yield Promise.all( validEmails, Promise.coroutine(function * (message){
      try{
        var person = yield People.findOne({email:  message.email }).exec();

        if(person){ 
          emailStatuses.push({status : "Already exists", email : message.email});
        }else{          
          emailsToSend.push({ email: message.email, message: message.text });
          }              
        }// else
      }catch(err){
        emailStatuses.push({status : "FAILURE", email : message.email}); 
      }//
    }));

    if( emailsToSend.length === 0){
      // no valid emails to process so just return              
      return res.status(200).json(emailStatuses);                     
    }// if no emails to send
    else{
      yield Promise.all(emailsToSend, Promise.coroutine(function * (emailMessage){
        try{                   
          var newInvite =  new Invite();  
          newInvite.email = emailMessage.email;
          newInvite.message = emailMessage.message;
          var invite = yield Invite.save();

          // now try to send the email
          var mailHTMl = html.replace( "{{EMAIL_PLACEHOLDER}}", req.body.registeredEmail);  

          var sendmail              = new emailProvider.Email();
          sendmail.setTos(emailMessage.email);
          sendmail.setFrom(common.DEF_EMAIL_SENDER);
          sendmail.setSubject(common.EMAIL_SUBJECT);
          sendmail.setHtml(mailHTMl);

          var successMail = yield emailProvider.send(sendmail);
          emailStatuses.push({status : "SUCCESS", email : emailMessage.email});
        }catch(err){
          //additional logging here which ive removed for purposes of brevity
          emailStatuses.push({status : "FAILURE", email : emailMessage.email});
        }           
      }));

      return res.status(200).json(emailStatuses);           
    }

  }).catch(function(err){
    //additional logging here which ive removed for purposes of brevity
    return res.status(500)
  });
我遇到的问题是Promise.all,如果我传入一个数组,它似乎只处理第一个元素,即使没有拒绝Promise或任何类型的错误

如果我使用Promise.each,这段代码是有效的,但是它是串行执行的。我想要实现的是,基本上有一个异步系列,包含2个async.foreach,它将一个接一个地执行并并行处理每个数组项,但会按顺序处理每个数组,类似于下面:

async.series([
  async.foreach
  async.foreach
]);

但是,为了让它并行执行,我不确定这里缺少了什么,因为如果我使用Promise.each并对每个数组项进行串行执行,它现在似乎可以正常工作。

因此基本上有两种方法来实现这一点,第一种解决方案是使用原始代码,只使用Promise.map,我不确定它是否并行执行,但基本上不会在第一个数组元素处停止

第二个是相当简单的更改,将数组值映射到协程函数,然后执行承诺。所有这些操作如下所示:

尽管我必须指出,这显然比使用async.js慢。如果有人能解释一下原因,那会很有帮助的

  co(function*(){  
    var re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
    var doc = yield People.findOne({email:  req.body.email}).exec();

    var filePath = path.join(__dirname, '../email-template.html');                         
    var html = yield fs.readFileAsync(filePath,'utf8');
    var emailsToSend = [];
    var emailStatuses = [];
    var validEmails = [];

    //make sure email is ok
    req.body.messagesToSend.forEach(function(message){
      if(message.email != null && re.test(message.email))
      { 
        validEmails.push(message);
      }else{
        // mark it as failed...
        emailStatuses.push({success : "FAILURE", email : message.email}); 
      }
    });

    //yield Promise.all( validEmails, Promise.coroutine(function * (message){
    var firstPromises = validEmails.map(Promise.coroutine(function * (message){  
      try{
        var person = yield People.findOne({email:  message.email }).exec();

        if(person){ 
          emailStatuses.push({status : "Already exists", email : message.email});
        }else{          
          emailsToSend.push({ email: message.email, message: message.text });
          }              
        }// else
      }catch(err){
        emailStatuses.push({status : "FAILURE", email : message.email}); 
      }//
    }));

    yield Promise.all(firstPromises);

    if( emailsToSend.length === 0){
      // no valid emails to process so just return              
      return res.status(200).json(emailStatuses);                     
    }// if no emails to send
    else{
      //yield Promise.all(emailsToSend, Promise.coroutine(function * (emailMessage){
      var secondPromises = emailsToSend.map( Promise.coroutine(function * (emailMessage){
        try{                   
          var newInvite =  new Invite();  
          newInvite.email = emailMessage.email;
          newInvite.message = emailMessage.message;
          var invite = yield Invite.save();

          // now try to send the email
          var mailHTMl = html.replace( "{{EMAIL_PLACEHOLDER}}", req.body.registeredEmail);  

          var sendmail              = new emailProvider.Email();
          sendmail.setTos(emailMessage.email);
          sendmail.setFrom(common.DEF_EMAIL_SENDER);
          sendmail.setSubject(common.EMAIL_SUBJECT);
          sendmail.setHtml(mailHTMl);

          var successMail = yield emailProvider.send(sendmail);
          emailStatuses.push({status : "SUCCESS", email : emailMessage.email});
        }catch(err){
          //additional logging here which ive removed for purposes of brevity
          emailStatuses.push({status : "FAILURE", email : emailMessage.email});
        }           
      }));

      yield Promise.all(secondPromises);

      return res.status(200).json(emailStatuses);           
    }

  }).catch(function(err){
    //additional logging here which ive removed for purposes of brevity
    return res.status(500)
  });

当然,有可能创造出一个关于
承诺的解决方案。所有的
问题?当然,
Promise.all
并不仅仅是查看你给它的数组中的第一个元素。因此,一个有针对性的测试用例将证明特定问题是一个可回答的问题。TJ,尽管它非常相似,但我可以将我的实际生产代码简化,这会有帮助吗?我只想补充一点,这在Promise.map或Promise.each中非常有效,但在Promise.all中不起作用