node.js / express / mongoose在异步函数中组合异步函数循环

时间:2020-05-12 14:55:04

标签: node.js express mongoose

我正在使用Node.js和猫鼬来获取数据。 在发送结果之前,我想遍历数据并获取另一个猫鼬集合的一些其他信息。

我无法管理它,第一个猫鼬呼叫正在等待,其他诺言已经完成。 我以为我的Promise和.then调用混在一起...:S

我的代码:

exports.checkChats = (req, res, next) => {
console.log(req.userData.userId);
let modifiedChats = [];
let partner;
Messages.find({ $or: [{ "users.starter": req.userData.userId }, { "users.partner": req.userData.userId }] })
    .then(chats => {
        if (chats) {
            console.log('Start');
            const promises = chats.map(async chat => {
                if (chat.users.starter.toString() === req.userData.userId.toString()) {
                    console.log('fetch partnerData for partner ' + chat.users.partner);
                    partner = chat.users.partner;
                }
                if (chat.users.partner.toString() === req.userData.userId.toString()) {
                    console.log('fetch partnerData for starter ' + chat.users.starter);
                    partner = chat.users.starter;
                }
                User.findById(partner).then(fetchedPartner => {
                    console.log('Partner fetched: ', fetchedPartner.userName);
                    modifiedChats.push({ id: chat._id, status: chat.status, lastMessage: chat.lastMessage, partnerName: fetchedPartner.userName, partnerImg: fetchedPartner.imagePath });
                });
            });
            Promise.all(promises).then(() => {
                console.log('End');
                res.status(201).json({
                    message: 'Chats found',
                    chats: modifiedChats
                });
            });
        }
    }).catch(error => {
        res.status(500).json({
            message: 'Couldnt fetch chats!',
            error: error
        });
    });
};

以及Terminallog:

Start
fetch partnerData for partner 5eb8502aad51b72012a2ccd1
fetch partnerData for partner 5eb84c93ad51b72012a2cc56
End
Partner fetched:  Summer
Partner fetched:  Pepe

谢谢你们。

1 个答案:

答案 0 :(得分:1)

嗨,您的代码中的问题位于此处

const promises = chats.map(async chat => {
  if (chat.users.starter.toString() === req.userData.userId.toString()) {
    console.log('fetch partnerData for partner ' + chat.users.partner);
    partner = chat.users.partner;
  }
  if (chat.users.partner.toString() === req.userData.userId.toString()) {
    console.log('fetch partnerData for starter ' + chat.users.starter);
    partner = chat.users.starter;
  }
  User.findById(partner).then(fetchedPartner => {
    console.log('Partner fetched: ', fetchedPartner.userName);
    modifiedChats.push({ id: chat._id, status: chat.status, lastMessage: chat.lastMessage, partnerName: fetchedPartner.userName, partnerImg: fetchedPartner.imagePath });
  });
});

此循环的每次迭代都调用User.findById(partner),该返回的状态是诺言并且是异步的。该函数不知道它需要等待其结果。 告诉函数等待User.findById(partner)完成的一种方法是添加return

return User.findById(partner).then(fetchedPartner => {
    console.log('Partner fetched: ', fetchedPartner.userName);
    modifiedChats.push({ id: chat._id, status: chat.status, lastMessage: chat.lastMessage, partnerName: fetchedPartner.userName, partnerImg: fetchedPartner.imagePath });
  });

您还可以删除异步输入

const promises = chats.map(async chat => {

这毫无用处,因为您始终没有使用async/await


这也是使用async/await重构代码的示例。

exports.checkChats = async (req, res, next) => { // by putting async here, you are enabling a function to use await
  try {
    console.log(req.userData.userId);
    let partner;
    const chats = await Messages.find({ $or: [{ "users.starter": req.userData.userId }, { "users.partner": req.userData.userId }] }); // by putting await before a function call the returns a promise, you will have the access to the value it will return by this syntax
    console.log('Start');
    const promises = chats.map(async chat => { // by putting async here, you are enabling a function to use await; This is also a function so you will need to put async here if you want to use await inside
      if (chat.users.starter.toString() === req.userData.userId.toString()) {
        console.log('fetch partnerData for partner ' + chat.users.partner);
        partner = chat.users.partner;
      }
      if (chat.users.partner.toString() === req.userData.userId.toString()) {
        console.log('fetch partnerData for starter ' + chat.users.starter);
        partner = chat.users.starter;
      }
      const fetchedPartner = await User.findById(partner); // same here, I put await because its a promise
      console.log('Partner fetched: ', fetchedPartner.userName);
      return { id: chat._id, status: chat.status, lastMessage: chat.lastMessage, partnerName: fetchedPartner.userName, partnerImg: fetchedPartner.imagePath }; // I am just returning the values here. By the end of the .map() it will have created an array of promises that each resolves the values return here
    });
    const modifiedChats = await Promise.all(promises); // this will convert the array of promises to an array of the values that was resolve  by each of the promises.
    console.log('End');
    res.status(201).json({
      message: 'Chats found',
      chats: modifiedChats
    });
  } catch (error) { // using try catch is the way for catching thrown errors / rejected promises
    res.status(500).json({
      message: 'Couldnt fetch chats!',
      error: error
    });
  }
};