Javascript异步等待不等待猫鼬等待

Posted

技术标签:

【中文标题】Javascript异步等待不等待猫鼬等待【英文标题】:Javascript async await not waiting for mongoose await 【发布时间】:2019-05-10 08:43:23 【问题描述】:

我正在尝试将数据库调用移出我的控制器以清理并使其可测试。当他们在控制器中时,一切都顺利进行。我将它们移出控制器并添加了异步以确保我们等待。否则,我会在Users.findOne().exec() 中调用res.render() 函数。现在,一旦我使用 async/await,我的控制器中的函数会认为没有用户,因为它没有等待。

关于异步等待有几个关于 SO 的问题,但我没有找到一个可以解决我的问题的问题。我确实验证了我的用户已返回,并添加了控制台日志以显示路径。

node mongoose async await 看起来很有希望,但他们的实际问题是未能退货,而我的退货很好 async not waiting for await 是 kotlin 的问题 async await not waiting 似乎非常适用,但我不完全理解关于嵌套等待/异步的答案 - 提问者遇到的问题比我的查询更复杂,因为他们正在处理循环和 forEach javascript async await 是正确的,所以我检查了 mongoose 函数是否返回了一个承诺。 Mongoose 文档显示它已准备好异步,因为调用返回一个承诺。

假设我们正在解析路由/users

routes/index.js

// requires & other routes not shown 
router.get('/users', controller.testUserShow);

控制器/index.js

// requires & other routes not shown 
   exports.testUserShow = async (req, res, next) => 
      if (req.user)  // if code to get user is right here, with no async/await, the user is found and the code continues
        try 
          found = await services.fetchUser(req.user._id)
          console.log("I am not waiting for at testusershow")
          console.log(found); //undefined
          // go on to do something with found
         catch(e) 
          throw new Error(e.message)
        
      
    

services/index.js

const db = require('../db')
exports.fetchUser = async (id) => 
  try 
    console.log("fetchUser is asking for user")
    return await db.returnUser(id)
   catch(e) 
    throw new Error(e.message)
  

db/index.js

const User = require('../models/user');
exports.returnUser = async (id) => 
  User.findById(id)
      .exec(function(err, foundUser) 
          if (err || !foundUser) 
              return err;
           else 
              // if this was in the controller 
              // we could res.render() right here
              console.log("returnUser has a user");
              console.log(foundUser); // this is a User
              return foundUser;
          
      );

控制台日志去

fetchUser is asking for user
I am not waiting for at testusershow
undefined
returnUser has a user
// not printed... valid user 

如果我调用的东西没有返回承诺,我希望初始调用是未定义的,但 User.findOne() 应该。

我错过了什么?

【问题讨论】:

你的函数returnUser 实际上并没有返回任何东西。 通过exec()调用,你可以传递一个回调函数,比如exec(cb)或者使用promise .exec().then(),听起来你需要使用后者。 【参考方案1】:

你的db/index应该是这样的:

exports.returnUser = (id) => 
  return User.findById(id);

当你不调用 exec 时,它会返回一个 promise。由于您的 services/index.js 已经使用 await 来获取响应,因此 db/index 不需要是异步函数。

【讨论】:

这是一个不错的简单方法。我喜欢它有多干净。由于我在实际函数中使用 .populate(),我将不得不使用 .exec().then(),但如果我不需要它会很漂亮。 @jessi 您可以在不使用 exec 或 then 的情况下使用 User.findById(id).populate(populate)。只需在 find 之后添加填充,它就会工作相同 哇 - 我不知道@iagowp - 我一直认为我必须继续得到它。【参考方案2】:

这是最简单的方法:

const User = require('../models/user');
exports.returnUser =  (id) => 
   return User.findById(id).exec().then(foundUser =>  
          console.log(foundUser); // this is a User
          return foundUser;
  );

如果你想使用 async/await 那么你可以这样做:

    exports.returnUser = async id => 
       const foundUser = await User.findById(id).exec();
       console.log(foundUser);
       return foundUser;
      );
    

如果你想使用回调,它看起来像:

exports.returnUser =  (id, cb) => 
   return User.findById(id).exec(cb);

关于 Mongoose 的一个很酷的想法是,如果您不传递回调,它将从 exec 函数/方法返回一个承诺。

【讨论】:

哇。我不敢相信我没有意识到关于 exec。这就是我把我的代码从一个地方拿出来而不是真正重写到新位置的结果。

以上是关于Javascript异步等待不等待猫鼬等待的主要内容,如果未能解决你的问题,请参考以下文章

猫鼬 findById 的异步/等待行为

将回调代码改进为异步等待猫鼬

在猫鼬中执行 CRUD 操作时异步/等待

NodeJS,从异步等待中获取返回值

JavaScript异步/等待:等待后代码不会继续[重复]

Java 不等待异步调用响应