await 仅在异步函数中有效 - 使用 mongoosejs exec() 时
Posted
技术标签:
【中文标题】await 仅在异步函数中有效 - 使用 mongoosejs exec() 时【英文标题】:await is only valid in async function - when using mongoosejs exec() 【发布时间】:2018-11-04 04:42:40 【问题描述】:我正在将一个 Hapi 项目移植到 v17 并在迁移到 async/await 时遇到了 Mongoose 的一些问题。
对于我在模型(猫鼬)上使用“等待”的任何代码,例如对象:
const result = await User.findOne(email: email).exec();
运行“node server.js”时出现以下异常
await User.findOne().exec();
^^^^^
SyntaxError: await is only valid in async function
at new Script (vm.js:74:7)
at createScript (vm.js:246:10)
at Object.runInThisContext (vm.js:298:10)
at Module._compile (internal/modules/cjs/loader.js:670:28)
at Object.Module._extensions..js
(internal/modules/cjs/loader.js:713:10)
at Module.load (internal/modules/cjs/loader.js:612:32)
at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
at Function.Module._load (internal/modules/cjs/loader.js:543:3)
at Module.require (internal/modules/cjs/loader.js:650:17)
at require (internal/modules/cjs/helpers.js:20:18)
我正在运行 node v10.2.0 和 mongoose 5.1.2,但无法理解为什么会出现错误。
mongoosejs 文档明确指出,如 here 所述,在使用 async/await 时应使用 exec() 来返回承诺。
有什么建议吗?
【问题讨论】:
在否决投票之前,您是否看过 mongoosejs 文档?因为他们声明“如果您使用的是 async/await,请等待 MyModel.findOne().exec()。”我认为它已经过测试并且是一个异步函数,否则为什么他们会在他们的文档中包含它。另外,我认为我不是世界上唯一一个同时使用 hapijs 和 mogoose 的人……还是我?这就是我寻求帮助的原因......而反对票只是你的傲慢! 【参考方案1】:await
只能在使用 async
关键字声明的函数内部使用。
async function doSomething()
let result = await someMongoooseFunctionThatReturnsAPromise();
// use result here
await
不能在async
函数之外使用。这就是你的错误告诉你的,它与猫鼬完全无关。它与调用 mongoose 函数的代码的结构有关。
注意: 任何 node.js 事件驱动代码都已经在函数中,因此要在该函数中使用 await
,您所要做的就是将 async
关键字添加到包含函数定义。如果该函数的调用者不期望任何返回结果,则不需要进一步更改。如果该函数的调用者期望返回结果,那么您必须调整调用代码以期望从 async
声明的函数返回一个承诺。
同样值得理解的是,async
函数总是返回一个承诺。虽然您可以像常规顺序代码一样编写它:
async function doSomething()
let result = await someMongoooseFunctionThatReturnsAPromise();
// use result here
result++;
return result;
这个函数实际上是返回一个promise,这个promise的解析值将是函数的返回值。所以,当你像这样使用async
函数时,你必须使用返回的promise:
doSomething().then(finalResult =>
console.log(finalResult);
);
因此,在您的特定代码中,如果您要使用 await
,它需要在 async
函数内:
async function someFunc()
const result = await User.findOne(email: email).exec();
// now this will work and you can use result here
或者,您可以改用.then()
:
User.findOne(email: email).exec().then(result =>
// process result here
// continue with other code that uses result here
);
注意:要在使用 async/await
时处理错误,您有两种选择:
您可以在任何async
声明的函数中使用传统的try/catch
,try/catch
将捕获来自await
的任何被拒绝的承诺。
如果你不使用 try/catch 并且你的函数中的 await
被拒绝,那么函数本身返回的承诺将被拒绝,你的函数的调用者将获得被拒绝的承诺。
所以,这取决于情况。如果您想在本地处理拒绝,那么您必须在 await
周围使用 try/catch(就像您使用 .catch()
一样。如果您希望拒绝冒泡给调用者,以便他们看到被拒绝的承诺,那么您不需要try/catch
,因为javascript 解释器会通过拒绝async
函数返回的承诺来自动冒泡被拒绝的await
。
【讨论】:
我赞成,你的解释很清楚。感谢您的帮助。 @MarcosCasagrande - 是的,无声的投票在这里是生活中的一个事实,但似乎一个简短的理由至少可以向作者提供他们做错了什么的反馈,并且充其量允许作者“修复”或改进他们的答案 - 从而使整个社区受益。 我知道,在投票时强制使用 cmets 会更好。 @MarcosCasagrande - 我不会走那么远(有时已经在评论中表达了这种情绪),但如果评论了一些合理的“为什么”,它将为社区的利益做出更多贡献. @MarcosCasagrande:这已经在元网站上讨论过、争论过、辩论过很多次了。例如:links。社区的决定一直是不这样做,因为它可能会被滥用,而且我们大多数人发现,在评论和否决时,我们通常不会得到问题或答案的改进,而是会得到争论。【参考方案2】:您需要将您的代码包含在这样的异步函数中
async function fetchFun()
const result = await User.findOne(email: email).exec();
console.log('Results fetched!'); //etc
fetchFun(); // <--
注意:您仍然必须在没有await
的情况下调用此函数,正如我用箭头指出的那样,因为您的代码必须有一些入口异步/等待代码(例如 C 中的 main()
) 并且那个入口函数不能用await
调用
【讨论】:
感谢您的积极反馈,我想过这样做,但这意味着我必须为每个 mongoose 调用添加额外的间接级别。我使用 Promise 的原始代码更加简洁优雅。 在我看来,这只会给你的代码增加一个层次,并且会消除一些混乱的.then()
链接
当跳转到async/await
世界时,你还必须使用try/catch
来处理你通常可以用.then(...).catch()
等处理的异常。但我认为async/await值得一试!
我投了赞成票。谢谢您的帮助。不知道为什么有人会否决你的答案。以上是关于await 仅在异步函数中有效 - 使用 mongoosejs exec() 时的主要内容,如果未能解决你的问题,请参考以下文章
SyntaxError:“await”仅在“async”函数中有效 - 需要帮助
await 仅对异步函数有效城市字典 api discord js