await仅在异步函数中有效 - 使用mongoosejs时exec()

cgi*_*omi 0 mongoose node.js hapijs

我正在将一个Hapi项目移植到v17,并在迁移到异步/等待时遇到Mongoose的一些问题.

使用'await'的任何代码,在模型(mongoose)上,对象例如:

const result = await User.findOne({email: email}).exec();
Run Code Online (Sandbox Code Playgroud)

运行'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)
Run Code Online (Sandbox Code Playgroud)

我正在运行节点v10.2.0和mongoose 5.1.2并且无法理解为什么我收到错误.

该mongoosejs文件明确指出,应该使用EXEC()使用异步何时返回承诺/等待是说这里

有什么建议?

jfr*_*d00 9

await只能在INSIDE中使用用async关键字声明的函数.

async function doSomething() {
    let result = await someMongoooseFunctionThatReturnsAPromise();
    // use result here
}
Run Code Online (Sandbox Code Playgroud)

await不能在async功能之外使用.这就是你的错误告诉你的事情,它与猫鼬完全无关.它与调用mongoose函数的代码结构有关.

注意:任何node.js事件驱动的代码在函数内部都是ALREADY,因此要await在该函数中使用,您所要做的就是将async关键字添加到包含函数定义的函数中.如果该函数的调用者不期望任何返回结果,则不需要进一步的更改.如果该函数的调用者期望返回结果,那么您必须调整调用代码以期望从async声明的函数返回promise .


同样值得理解的是,async函数总是返回一个promise.虽然您可以像常规顺序代码一样编写它:

async function doSomething() {
    let result = await someMongoooseFunctionThatReturnsAPromise();
    // use result here
    result++;
    return result;
}
Run Code Online (Sandbox Code Playgroud)

该函数实际上返回一个promise,该promise的解析值将是函数的返回值.因此,当您使用这样的async函数时,您必须使用返回的promise:

 doSomething().then(finalResult => {
     console.log(finalResult);
 });
Run Code Online (Sandbox Code Playgroud)

因此,在您的特定代码中,如果您要使用await,则需要在async函数内部:

async function someFunc() {
    const result = await User.findOne({email: email}).exec();
    // now this will work and you can use result here
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用.then():

User.findOne({email: email}).exec().then(result => {
    // process result here
    // continue with other code that uses result here
});
Run Code Online (Sandbox Code Playgroud)

注意:要在使用时处理错误async/await,您有两种选择:

  1. 你可以使用传统的try/catch任何async声明的函数,try/catch并将捕获任何被拒绝的承诺await.

  2. 如果您不使用try/catch并且await函数内部拒绝,则函数本身返回的承诺将被拒绝,并且函数的调用者将获得被拒绝的承诺.

所以,这取决于具体情况.如果你想在本地处理拒绝,那么你必须使用try/catch await(就像你想的那样.catch().如果你想让拒绝泡到呼叫者那么他们会看到被拒绝的承诺,那么你就不需要了try/catch因为Javascript解释器会await通过拒绝async函数返回的promise来自动冒泡拒绝.

  • @MarcosCasagrande-是的,无声无语是这里的现实,但似乎有一个简单的理由至少可以为作者做错了事情提供反馈,并充其量让作者“修复”或改进答案-从而使整个社区受益。 (2认同)
  • @MarcosCasagrande - 我不会走得那么远(有时候评论中已经表达了这种情绪),但如果对某些合理的"为什么"进行评论,它将为社区的利益做出更多贡献. (2认同)