【问题标题】:How to handle this javascript asynchronous function如何处理这个javascript异步函数
【发布时间】:2021-08-24 19:42:11
【问题描述】:

我在javascript节点中有这个功能

exports.getUserEmailByAccess = async (moduleType) => {
  let emailList = []
  const foundUsers = await Access.find({moduleType:moduleType})
  console.log(foundUsers);

  await foundUsers.forEach(access => {
      User.findById(access.userId)
      .then(foundUser => {
          console.log(foundUser.workerEmail);
          emailList.push(foundUser.workerEmail)
      })
      
  });

   console.log(emailList);
   return emailList

}

我想要的是通过循环对象数组推入 emailList 数组,上述方法导致一个空数组,所以我尝试了以下不同的方式

exports.getUserEmailByAccess = async (moduleType) => {
  let emailList = []
  const foundUsers = await Access.find({moduleType:moduleType})
  console.log(foundUsers);

  await foundUsers.forEach(access => {
      const foundUser = User.findById(access.userId)
      console.log(foundUser.workerEmail);
      emailList.push(foundUser.workerEmail)
      
  });
  console.log(emailList);

  return emailList

 
}

通过这样做,数组列表被填满,但有一个 [undefined]strong text 值,我来自一个不起眼的 python 控制结构背景,请我知道为什么我不能即使在使用 async/await 之后也将数据推送到数组中

【问题讨论】:

  • 确实 foundUsers.forEach 返回一个 Promise - 如果没有,你不能等待它......我假设那不是数组forEach,在这种情况下,永远不要将 Array forEach 与 async/await 一起使用,除非你真的知道自己在做什么——即使那样,总有更好的方法来做到这一点
  • @Bravo 是对的,forEach 不会等待承诺被解决,而是应该使用for 循环。
  • 答案取决于您是否可以并行或串行User.findById

标签: javascript node.js asynchronous async-await


【解决方案1】:

如果User.findById() 返回一个承诺,我建议使用Promise.all() 而不是使用forEach 单独运行所有承诺来获取所有foundUsers 的文档:

exports.getUserEmailByAccess = async (moduleType) => {
  const foundUsers = await Access.find({ moduleType: moduleType });
  console.log(foundUsers);

  const userDocs = await Promise.all(
    foundUsers.map((user) => User.findById(user.userId))
  );
  const emailList = userDocs.map((user) => user.workerEmail);
  // or alternatively
  // const emailList = userDocs.map(({workerEmail}) => workerEmail);

  console.log(emailList);
  return emailList;
};

【讨论】:

    【解决方案2】:

    你可以试试这个

    exports.getUserEmailByAccess = async (moduleType) => {
        let emailList = []
        const foundUsers = await Access.find({ moduleType: moduleType })
        console.log(foundUsers);
    
        await foundUsers.map(async access => {
            let result = await User.findById(access.userId);
            if (result) {
                emailList.push(foundUser.workerEmail)
            }
    
        });
    
        console.log(emailList);
        return emailList
    }
    

    更新

    await Promise.all(
         foundUsers.map(async access => {
            let result = await User.findById(access.userId);
            if (result) {
                emailList.push(foundUser.workerEmail)
            }
    
        })
    ])
    
    console.log(emailList);
    return emailList
    

    【讨论】:

    • map 不会等待异步函数被解析,emailList 将保持为空。
    • 数组映射也不返回 Promise - 所以这同样糟糕......如果你想并行处理,通常它类似于 await Promise.all(array.map .....
    • 是的,它仍然返回空数组
    【解决方案3】:

    您的模型是如何关联的?如果访问模型具有用户模型的 ObjectId,我认为您可能会在此处进行填充。像这样的:

    const foundUsers = await Access.find({ moduleType: moduleType }).populate({
      path: 'users', // the name of the field which contains the userId
      select: '-__v' // fields to bring from database. Can add a (-) to NOT bring that field
    })
    

    这个想法是您指定您需要的所有字段。然后当您收到数据时,您可以执行以下操作:

    foundUsers.users.email
    

    【讨论】:

    • “可以添加 (-) 以不带该字段”,您还可以在查询中使用 projections 指定它
    猜你喜欢
    • 2012-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-08
    • 1970-01-01
    • 2018-12-12
    • 2014-11-05
    • 1970-01-01
    相关资源
    最近更新 更多