因为我无法在顶层运行等待,所以我必须将其放入异步函数中 - 为什么我可以直接调用该异步函数?

fin*_*oot 7 javascript asynchronous node.js async-await

我有一个简短的 Node.js 脚本,我需要另一个包并从中调用异步函数,然后想要打印返回值。如果我只是await从顶层返回值,那么我会得到一个错误,说我只能await在异步函数本身内部使用。所以显然要走的路是这样的:

async function main() {
  foo = await someOtherAsyncFunc();
  console.log(foo);
}
main()
Run Code Online (Sandbox Code Playgroud)

或者:

(async function() {
  foo = await someOtherAsyncFunc();
  console.log(foo);
})();
Run Code Online (Sandbox Code Playgroud)

或者:

(async () => {
  foo = await someOtherAsyncFunc();
  console.log(foo);
})();
Run Code Online (Sandbox Code Playgroud)

(感谢聊天中的 VLAZ https://chat.stackoverflow.com/transcript/message/54186176#54186176

这是可行的 - 但我想更多地了解其背后的原因:我习惯了无法直接await从顶层使用。然而,我也习惯于必须调用一些特殊的库函数才能真正从顶层“冒险”进入异步。在 Python 中,请参见asyncio.run示例。await如果我可以从顶层调用任何异步函数,那么要求位于异步函数内有什么意义?那么为什么await顶层也不可用呢?

Cer*_*nce 6

顶级等待过去并不是什么,但现在在 ES6 模块中是可能的。

顶级等待过去不是一个东西,并且仍然不是模块之外的一个东西,原因之一是它可能允许语法歧义。async 和await 是有效的变量名称。模块之外。如果非模块脚本允许顶级等待,那么,如果不重新设计规范(并破坏向后兼容性),则在某些情况下解析器无法确定 的特定实例是否是await变量名,或者用作等待右侧 Promise 解析的语法。

为了避免任何歧义的可能性,解析器在解析一段代码时,本质上需要有标志来指示await在任何给定点作为标识符是否有效,或者作为异步语法是否有效,并且这两者绝不能相交。

模块脚本允许顶级等待(现在),因为在它们中一直禁止使用await作为标识符,因此不存在语法歧义。

.then相比之下,在顶层使用的问题为零,因为它在任何情况下都不会导致任何歧义。

为什么它不只返回一个从未执行过的 Promise,因为它没有被等待?

承诺并没有真正“执行”。它们可以被构造,或者等待实现,或者等待拒绝。如果您有 Promise,那么您已经有一些正在进行的代码,这些代码(可能)最终会导致将履行值分配给 Promise。

悬挂 Promise 在语法上是允许的 - 解析为 Promise 但不与其他地方交互的值。(这是有道理的 -每个 .thenor.catch都会产生一个新的 Promise。如果每个 Promise 都必须被其他东西使用,那么你最终会陷入无限倒退。)

正在做

(async () => {
  foo = await someOtherAsyncFunc();
  console.log(foo);
})();
Run Code Online (Sandbox Code Playgroud)

本质上是语法糖

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

没有必要在其中任何一个的末尾添加任何其他内容。(尽管建议悬空的 Promise 中添加 a .catch,这样就不会发生未处理的拒绝)