我正在将一个快乐的项目移植到 v17 并在移动到 async/await 时遇到一些 Mongoose 问题。
对于我的任何使用"await"的代码,在模型(猫鼬(上,例如对象:
const result = await User.findOne({email: email}).exec();
运行"节点服务器.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)
我正在运行节点 v10.2.0 和猫鼬 5.1.2,但不明白为什么我会收到错误。
mongoosejs 文档明确指出,在使用 async/await 时应该使用 exec(( 返回承诺,如此处所述
有什么建议吗?
await
只能在使用async
关键字声明的函数中使用。
async function doSomething() {
let result = await someMongoooseFunctionThatReturnsAPromise();
// use result here
}
await
不能在async
函数之外使用。 这就是你的错误告诉你的,它与猫鼬完全无关。 它与调用猫鼬函数的代码的结构有关。
注意:任何节点.js事件驱动的代码都已经在函数中,因此要在该函数中使用await
,您所要做的就是将async
关键字添加到包含函数定义的字符串中。 如果该函数的调用方不需要任何返回结果,则无需进一步更改。 如果该功能的调用方期望返回结果,则必须调整调用代码以期望从async
声明的函数返回承诺。
同样值得理解的是,async
函数总是返回一个承诺。 虽然您可以像常规顺序代码一样编写它:
async function doSomething() {
let result = await someMongoooseFunctionThatReturnsAPromise();
// use result here
result++;
return result;
}
此函数实际上返回一个承诺,该承诺的解析值将是函数的返回值。 因此,当您使用这样的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
。
你需要像这样的异步函数中包围你的代码
async function fetchFun() {
const result = await User.findOne({email: email}).exec();
console.log('Results fetched!'); //etc
}
fetchFun(); // <--
注意:正如我用箭头指出的那样,您仍然必须在没有await
的情况下调用此函数,因为您的代码 async/await 代码必须有一些入口(如 C 中的main()
(,并且该入口函数不能用await
调用