2016-05-18 11 views
-1

cobluebird.jsの両方を使用して、コルーチンと約束を使用してasync.jsライブラリの制御フローを模倣しようとしていますが、いくつかの問題があります。次のように私のコードは...ノードCoroutinesジェネレータとプロミスによる並列フロー制御

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

持つ問題Imがである実際のコードが非常に長くなってきてしまうため、これは主に擬似コードは、私が後で必要に応じてacutalコードを追加することができ、ですが、ありますPromise.all、もし私が配列を渡すならば、それは約束や何らかのエラーの拒否もなくても、最初の要素を処理するように見えます。

このコードは、Promise.eachを使用すると機能しますが、その後はシリアルで実行されます。私は何を達成したいことは基本的に並列に配列の各要素次々と処理を実行します2 async.foreachと非同期シリーズを持っていますが、一種の下記のように、各配列を順次処理されます。

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

しかし、 Promise.eachを使用して、各配列項目のシリアル実行を取得すると、今は正常に動作しているように見えるので、私がここで行方不明になっているかどうかはわかりません。

+0

は、確かにそれは[MCVE] 'Promise.all'の問題を作成することが可能ですか? Fundamentall、もちろん、 'Promise.all' *は配列の最初の要素を見ていません。したがって、特定の問題が解決可能な質問であることを証明する目的のテストケース。 –

+0

TJ、その非常によく似ていますが、実際の生産コードを最小限に抑えることができますが、それは役に立ちますか? –

+0

私は、これがPromise.mapまたはPromise.eachでは完全にうまくいくと付け加えたいと思いますが、Promise.allではうまく動作しません –

答えて

0

基本的に2つの方法がありますが、最初の解決策は元のコードを使用してPromise.mapを使用することです。これは並列で実行するかどうかわかりませんが、基本的には最初の配列要素。

第二の機能をコルーチンする配列の値をマッピングし、その後、以下に示すもののようにPromise.allを行うための非常に単純な変更である:私は、これが非同期を使用するよりも目に見えて遅くなり、注意しなければならない、が

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