使用带有 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
,它们隐式返回Promise
1。
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 employees
和throw 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 未定义