2017-12-27 7 views
0

약속 루프를 사용하는 방법, 내 문제가 해결 호출하는 곳과 관련이있다 생각하지만 난 잘 모르겠어요내가 더 성공을 약속 내에서 루프를 실행하기 위해 노력하고있어

/* 
 
* Get conversations of user 
 
* @param user {String} 
 
*/ 
 
function getConversations(user){ 
 
\t return new Promise(function(resolve, reject){ 
 
\t \t var conversations = user.Conversations 
 
\t \t var newConversations = [] 
 
\t \t for(var conversation of conversations) { 
 
\t \t \t helperGetConvo(conversation.ConversID).then(function(convo){ 
 
\t \t \t \t newConversations.push(createConversationObject({messages:[], name:convo.conversationName, users:["broulaye", "doumbia"], Id:convo.conversationID})) 
 

 

 
\t \t \t }).catch(function(reason) { 
 
\t \t \t \t console.log("failure when finding conversation 2: " + reason) 
 
\t \t \t }) 
 

 
\t \t } 
 
\t \t resolve(newConversations) 
 

 

 

 
\t }) 
 
} 
 

 

 
function helperGetConvo(convoId) { 
 
\t return new Promise (function(resolve, reject){ 
 
\t \t query.findConversation(convoId).then(function(convers) { 
 

 
\t \t \t if(convers) { 
 
\t \t \t \t console.log("conversation was found: " + convers) 
 
\t \t \t } 
 
\t \t \t else { 
 
\t \t \t \t console.log("conversation was not found: " + convers) 
 
\t \t \t } 
 
\t \t \t resolve(convers) 
 
\t \t }).catch(function(reason) { 
 
\t \t \t console.log("failure when finding conversation: " + reason) 
 
\t \t }) 
 

 

 
\t }) 
 
}

이와 같은 코드를 실행할 때 getConversations 함수는 빈 배열 만 반환합니다. 내가 getConversations을 변경할 때하지만 지금 같은 기능 :

function getConversations(user){ 
 
\t return new Promise(function(resolve, reject){ 
 
\t \t var conversations = user.Conversations 
 
\t \t var newConversations = [] 
 
\t \t for(var conversation of conversations) { 
 
\t \t \t helperGetConvo(conversation.ConversID).then(function(convo){ 
 
\t \t \t \t newConversations.push(createConversationObject({messages:[], name:convo.conversationName, users:["broulaye", "doumbia"], Id:convo.conversationID})) 
 
\t \t \t \t resolve(newConversations) 
 

 
\t \t \t }).catch(function(reason) { 
 
\t \t \t \t console.log("failure when finding conversation 2: " + reason) 
 
\t \t \t }) 
 

 
\t \t } 
 
\t }) 
 
}

내가 그러나 그것은 내가 믿는 전체 forloop 통과하지 않는 출력을 얻을 때문에 return 문처럼 내 이해 해결 작업에서 .

누군가의 도움이 PLZ

+3

약속이 해결 될 때까지 기다려야합니다. Promise.all을 살펴보십시오. 나는 또한 약속에 대한 더 많은 독서를 조언 할 것이고, 당신의 코드는 정말로 엉망이다. –

+0

[약속 생성자 방지 패턴] 방지 (https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it) –

답변

2

당신은

function getConversations(user){ 
    var conversations = user.Conversations 
    var promises = conversations.map(c=>helperGetConvo(c.ConversID)) 

    return Promise.all(promises) 
     .then(data=>{ 
      let newConversations = data.map(convo=>{ 
       return createConversationObject({messages:[], name:convo.conversationName, users:["broulaye", "doumbia"], Id:convo.conversationID}) 
      }) 
      return newConversations 
     }) 
     .catch(reason=>{ 
      console.log("failure when finding conversation: " + reason) 
     }) 
} 

Promise.all이 문제는 전화 할 때 resolve는 전체 약속을 해결하는 것입니다 그래서

getConversations(user).then(newConversations=>{ 
    //your code 
}) 
+0

이 작품은 큰 감사합니다 –

1

한 가지 방법은 배열을 사용하여 맵에 대신위한-의 약속을 수집하는 것입니다. 그런 다음 Promise.all()을 사용하여 모든 항목이 해결 될 때까지 기다리십시오. 같은

뭔가 :

return Promise.all(conversations.map(conversation => { 
    return helperGetConvo(...).then().catch(); 
} 

모든 약속 해결하거나 거부해야 하나 기억하십시오. 이 규칙을 따르지 않으면 문제가 생길 수 있습니다.

+0

많이 고마워 할 것입니다 –

1

같은 기능을 사용하여 사용해야합니다. for 루프는 각 helperGetConvo() 호출이 끝날 때까지 기다리지 않고 다음 호출로 이동합니다. 어떤 약속이든 then 진술 문을 먼저 치면 resolve으로 전화를 걸고 외부 약속이 해결됩니다.

약속에 대한 자세한 내용은 Understanding promises in node.js에서 확인할 수 있습니다.

약속을 끝내기를 기다리려면 Promise.all을 사용하십시오. 약속 목록을 받아들이고 모든 약속이 성공적으로 완료되면 해결됩니다.

function getConversations(user) { 
    return new Promise(function (resolve, reject) { 
    var conversations = user.Conversations; 
    var newConversations = []; 
    //create a list of promises 
    var promises = []; 
    for (var conversation of conversations) { 
     // push each promise into our array 
     promises.push(
     helperGetConvo(conversation.ConversID).then(function (convo) { 
      newConversations.push(createConversationObject({ 
      messages: [], 
      name: convo.conversationName, 
      users: ['broulaye', 'doumbia'], 
      Id: convo.conversationID 
      })); 
     }).catch(function (reason) { 
      console.log('failure when finding conversation 2: ' + reason); 
     }) 
    ); 

    } 
    // wait for all promises to complete 
    // when then do, resolve the newConversations variable 
    // which will now have all of the conversation objects that we wanted to create 
    Promise.all(promises).then(() => resolve(newConversations)).catch(reject); 
    }); 
} 

async/await를 사용하여이를 정리할 수도 있습니다. 비동기/대기는 return new Promise(...)을 수행 할 필요가 없으므로 구문법이 좋은 설탕을 제공합니다. 이 다음 코드 스 니펫은 for 루프가 모든 것을 동 기적으로 처리하므로 (한 번에 하나의 대화) async/await를 사용하는 가장 좋은 방법은 아닙니다. 이 블로그 게시물은 반복 문제에서 async/await를 사용하는 것에 대한 나의 이해에 크게 도움이되었습니다. https://blog.lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795.

async function getConversations(user) { 
    var conversations = user.Conversations; 
    var newConversations = []; 

    // process each converstaion in sequence 
    for (var conversation of conversations) { 
     // instead of doing .then() we can use await 
     // convo will have the result from the helperGetConvo 
     // we put it in a try/catch because output 
     // we still want to have the error if something fails 
     try { 
     var convo = await helperGetConvo(conversation.ConversID); 
     newConversations.push(createConversationObject({ 
      messages: [], 
      name: convo.conversationName, 
      users: ['broulaye', 'doumbia'], 
      Id: convo.conversationID 
     })); 
     } catch(reason) { 
     console.log('failure when finding conversation 2: ' + reason); 
     } 
    } 

    // return 
    return newConversations; 
} 

비동기 함수는 약속을 반환합니다. 따라서 getConversations(user).then(...)을 실행하여이 함수를 호출 할 수 있습니다. 하지만 async/await는 코드가 훨씬 깨끗해 보일 것이라고 생각합니다. 확실히 더 많은 최적화가 가능하지만 잘하면이 작업을 시작할 수 있습니다.

+0

당신은 불필요한 약속을하고 있습니다. http://bluebirdjs.com/docs/anti-patterns.html#the-explicit-construction-anti-pattern –

+0

아마도. 가능한 한 OP의 원래 코드를 그대로두고 그 구조 내에서'Promise.all '을 어떻게 활용할 수 있는지 보여 주려고했습니다. 내가 선택할 수 있다면이 모든 것을 비동기식으로 변경했거나 정리하기를 기다리고있을 것입니다. – TheF1rstPancake

+0

@EricGuan yea 나는 아마 내가 너무 익숙하지 않아서 그 이유를 알고있다. –

1

비슷한 문제를 해결할 때 찾은 도우미 기능 내에서 약속을 반복 할 수 있습니다. 첫 번째 거부 된 약속에서 넘어지지 않으므로이 방법을 사용하여 약속을 반복합니다. 대신 해결 또는 거부 처리 할 수 ​​있으며 루프가 완료되면 최종 결과를 반환합니다. 아래 코드의 약속은 좀 더미 데이터를 제공하는 코드 예제를 수정하고 도우미 기능을 작동 할 수있어 http://bluebirdjs.com/docs/getting-started.html

function promiseWhile(condition, action) { 
     return new Promise((resolve, reject) => { 

      var loop =() => { 
       if (!condition()) return resolve(); 
       return Promise.cast(action()) 
        .then(loop) 
        .catch(reject); 
      }; 

      process.nextTick(loop); 
      return resolve; 
     }) 
    } 

, 블루 버드 사용하고 있습니다. 결과적으로 getConversations 함수는 다음과 같을 것입니다.

function getConversations(user) { 
     var conversations = user.Conversations; 
     var newConversations = []; 

     var stop = conversations.length; 
     var index = 0 

     //loop promise 
     return promiseWhile(() => { 
      // Condition for stopping 
      return index < stop; 
     },() => { 
      // Action to run, should return a promise 
      return new Promise((resolve, reject) => { 
       helperGetConvo(conversations[index].ConversID) 
        .then(function(convo) { 
          newConversations.push(createConversationObject({ 
          messages: [], 
          name: convo.conversationName, 
          users: ['broulaye', 'doumbia'], 
          Id: convo.conversationID 
          })); 
          index++; 
          resolve(); 
         }) 
         .catch((error) => { 
          console.log('failure when finding conversation: ' + error); 
          index++; 
          resolve(); 
         }); 
      }) 
     }) 
      //This will execute when loop ends 
      .then(() => { 
       return newConversations; 
      }); 
    } 

희망이 있습니다.

관련 문제