如何在promises

时间:2017-12-27 22:06:10

标签: node.js reactjs promise

我试图在承诺中执行for循环但没有成功,我认为我的问题与调用解析的位置有关,但我不确定



/*
* Get conversations of user
* @param user {String}
*/
function getConversations(user){
	return new Promise(function(resolve, reject){
		var conversations = user.Conversations
		var newConversations = []
		for(var conversation of conversations) {
			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)
			})

		}
		resolve(newConversations)



	})
}


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

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


	})
}




当我执行这样的代码时,getConversations函数只返回一个空数组。但是当我像这样更改getConversations函数时:



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

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

		}
	})
}




我确实得到了一个输出,但它没有通过整个forloop我相信,因为从我的理解解决工作就像一个返回声明。

有人帮助PLZ

4 个答案:

答案 0 :(得分:2)

您需要使用Promise.all

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

使用像这样的功能

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

答案 1 :(得分:1)

一种方法是使用map而不是for-in来收集数组中的promise。然后使用Promise.all()等待所有这些解析(或拒绝一个)。

类似的东西:

mouse out

记住所有承诺必须解决或拒绝。如果你不遵守这条规则就会遇到麻烦。

答案 2 :(得分:1)

问题在于,当你致电resolve时,你正在解决整个承诺。 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来清理它。 Async / await提供了一些很好的语法糖,无需执行return new Promise(...)。下一个代码片段不是使用async / await的最佳方式,因为for循环将同步处理所有内容(一次一个会话)。这篇博文非常有助于我理解在迭代问题中使用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;
}

异步函数返回promise。所以你可以通过getConversations(user).then(...)来调用这个函数。但我认为async / await使您的代码看起来更清晰。肯定会有进一步的优化,但希望这可以让你开始。

答案 3 :(得分:1)

你可以在我试图解决类似问题时找到的辅助函数中循环一个promise。我使用这种方法来循环承诺,因为它不会在第一个被拒绝的承诺中失败。相反,我可以处理解决方案或拒绝并在循环结束后返回最终结果。下面的代码段中的Promise使用bluebird,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;
            });
    }

希望这有帮助。