使用带有 async/await 的 mongoose 承诺

Posted

技术标签:

【中文标题】使用带有 async/await 的 mongoose 承诺【英文标题】:Using mongoose promises with async/await 【发布时间】:2018-03-09 11:37:50 【问题描述】:

我正在尝试将 Mongoose Promise 与 Node.js 的 async/await 功能结合使用。当我的函数printEmployees 被调用时,我想保存orderEmployees 函数查询的员工列表。而orderEmployees 中的console.log 语句返回了预期的查询,printEmployees 中的console.log 返回了undefined,这表明我没有正确返回承诺。

我完全不熟悉承诺,以至于我没有正确理解范式......非常感谢任何帮助。

  printEmployees: async(company) => 
    var employees = await self.orderEmployees(company);
    // SECOND CONSOLE.LOG
    console.log(employees);
  ,

  orderEmployees: (companyID) => 
    User.find(company:companyID)
    .exec()
    .then((employees) => 
      // FIRST CONSOLE.LOG
      console.log(employees);
      return employees;
    )
    .catch((err) => 
      return 'error occured';
    );
  ,

【问题讨论】:

【参考方案1】:

为了使orderEmployees 表现得像异步函数,您必须返回结果承诺。使用不带 async/await 关键字的 Promise 时需要遵循两条规则:

    如果函数返回Promise,则该函数是异步的 如果您有一个承诺(例如由异步函数返回),则必须对其调用 .then 或将其返回。

当您使用 async/await 时,您必须 await 兑现您获得的承诺。

这表示你会注意到你没有返回在orderEmployees 中生成的承诺。很容易修复,但也很容易将该函数重写为异步。

orderEmployees: (companyID) => 
  return User.find(company:companyID) // Notice the return here
  .exec()
  .then((employees) => 
    // FIRST CONSOLE.LOG
    console.log(employees);
    return employees;
  )
  .catch((err) => 
    return 'error occured';
  );
,

orderEmployees: async(companyID) => 
  try 
    const employees = await User.find(company:companyID).exec();
    console.log(employees);
    return employees;
   catch (err) 
    return 'error occured';
  
,

PS:这里的错误处理有些缺陷。我们通常不会通过从函数返回错误字符串来处理错误。在这种情况下,最好让错误传播,并从一些*** UI 代码中处理它。

【讨论】:

嗨,你能做 async(companyID) => await User.find(company:companyID).then(data => return data ).catch(err => return err .message ) @ODaneBrissett 到底是什么问题?你写的代码有很多问题,它不会工作。从技术上讲,您可以将 await 和 then 混合使用,但我建议您不要这样做,因为它很容易出错。只需使用异步等待。 try return await User.find(); catch(e) showerror(e.message); // dont return the error message, you never want to do that 我只是在寻求澄清,看看我的方法是否可行。但感谢您的意见。你能说为什么它不起作用 @O'DaneBrissett 我注意到 4 件事,1:异步函数没有返回任何东西 2:.then(data => return data ) 没有做任何事情,它只是评估为具有相同分辨率值的类似承诺, 3:.catch(err => return err.message ) 将隐藏异常,使处理错误变得不可能,4:一个危险信号是异步函数中没有等待 嗯,这很有趣,但是,这是我下面的完整实现,它可以工作 exports.getLoan = async (req, res) => await Loans.findById(req.params.id) .then(data => if (!data) return res.status(404).send('Sponsored product not found') res.send(data) ) .catch(err => return res.status(500).send( message: err.message ) ) 只是控制器中的一种方法。我进行了测试,它捕获了错误并返回了响应。我只是想知道这种方法是否有任何错误【参考方案2】:

你需要return你的Promise

目前,您正在等待返回 undefined 的函数。 await 仅在与 Promise 一起使用时才真正“等待”该值。 始终牢记you can only await Promises 或async functions,它们隐式返回Promise1
orderEmployees: (companyID) => 
  return User.find( company:companyID ).exec()

同样重要的是,您应该在 .catch 处理程序中使用 throw 而不是 return。从.catch 处理程序中返回将导致承诺链触发它的.then 而不是.catch,从而破坏错误处理链。

更好的是,根本不要包含.catch,让实际错误在承诺链中冒泡,而不是用您自己的非描述性'error occured' 消息覆盖它。

错误条件应该抛出错误,而不是返回它。


1 您也可以等待非 Promise,但仅限于同步评估的值。

【讨论】:

【参考方案3】:

您没有从 orderEmployees 返回 Promise。

printEmployees: async(company) => 
  var employees = await self.orderEmployees(company);
  // SECOND CONSOLE.LOG
  console.log(employees);
,

orderEmployees: (companyID) => 
  return User.find(company:companyID)
 .exec()
 .then((employees) => 
   // FIRST CONSOLE.LOG
   console.log(employees);
   return employees;
 )
 .catch((err) => 
   return 'error occured';
 );
,

【讨论】:

【参考方案4】:

你需要从orderEmployees返回一个Promise

orderEmployees: companyId => User.find( companyId ).exec()

如果您想在返回之前进行一些错误处理或预处理,那么您可以保持您的代码不变,但请记住返回结果(promise 是可链接的)。

【讨论】:

我看不出explicit promise creation antipattern 将如何帮助处理错误。有什么好处?你可以从一个简单的异步函数中获取return employeesthrow e @TamasHegedus 是的,好点,Node 不能很好地处理从内部承诺抛出异常的旧习惯!【参考方案5】:

如果您要使用 async/await,那么它的工作原理是这样的。

在返回承诺的函数前面等待。 async 在包装函数前面。 将函数体包装在 try/catch 块中。

请看一下这个函数,它是一个中间件 在我在 express 中执行特定路线之前。

const validateUserInDB = async (req, res, next) => 
    try 
        const user = await UserModel.findById(req.user._id);
        if (!user) return res.status(401).json( message: "Unauthorized." );
        req.user = user;
        return next();
     catch (error) 
        return res.status(500).json( message: "Internal server error." )
    

await 之后的代码正在等待 promise 被解析。 catch 块会捕获 try 块内发生的任何错误,即使 catch 方法触发的错误来自等待 promise。

【讨论】:

以上是关于使用带有 async/await 的 mongoose 承诺的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 async/await 的 mongoose 承诺

使用带有 async\await 的 mysql 池 |节点JS

使用 jasmin 使用带有 async/await 的 $httpBackend 测试角度服务

在node.js中使用带有async / await的文件系统

如何在带有 vuex 的 vue 生命周期钩子中使用 async/await?

使用带有 webpack-simple 配置的 async/await 抛出错误:RegeneratorRuntime 未定义