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

await is only valid in async function - when using mongoosejs exec()

我正在将一个 Hapi 项目移植到 v17,并且 运行 在迁移到 async/await 时遇到一些 Mongoose 问题。

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

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 文档明确指出,在使用 async/await 时应使用 exec() 来 return 承诺 here

有什么建议吗?

您需要像这样用异步函数包围您的代码

async function fetchFun() {
  const result = await User.findOne({email: email}).exec();

  console.log('Results fetched!'); //etc
}

fetchFun(); // <--

注意: 你仍然需要在没有 await 的情况下调用这个函数,正如我用箭头指出的那样,因为你的代码必须有一些入口 async/await 代码(如 C 中的 main())并且入口函数不能用 await

调用

await 只能在使用 async 关键字声明的函数内部使用。

async function doSomething() {
    let result = await someMongoooseFunctionThatReturnsAPromise();
    // use result here
}

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

注意:任何node.js事件驱动的代码已经在一个函数中,所以要在那个函数中使用await,你所要做的就是将 async 关键字添加到包含函数定义的关键字中。如果该函数的调用者不期望任何 return 结果,则不需要进一步更改。如果该函数的调用者期望 return 结果,那么您必须调整调用代码以期望从 async 声明的函数中 returned 承诺。


还值得理解的是,async 函数总是 return 是一个承诺。虽然您可以像常规顺序代码一样编写它:

async function doSomething() {
    let result = await someMongoooseFunctionThatReturnsAPromise();
    // use result here
    result++;
    return result;
}

此函数实际上是 return 承诺,该承诺的解析值将是函数的 return 值。所以,当你像这样使用 async 函数时,你必须使用 returned 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 时处理错误,您有两个选择:

  1. 您可以在任何 async 声明的函数中使用传统的 try/catch 并且 try/catch 将捕获来自 await.[=38 的任何被拒绝的承诺=]

  2. 如果您不使用 try/catch 并且函数内部的 await 被拒绝,那么函数本身 return 的承诺将被拒绝并且你的函数的调用者将得到被拒绝的承诺。

所以,这要视情况而定。如果你想在本地处理拒绝,那么你必须在 await 周围使用 try/catch(就像你使用 .catch() 一样)。如果你希望拒绝冒泡到调用者,那么他们会看到被拒绝的承诺,那么你不需要 try/catch 因为 Javascript 解释器会通过拒绝 async 函数 [=75] 的承诺来自动冒泡被拒绝的 await =]s.