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

Because I can't run await on the top level, I have to put it into an async function - why can I then call that async function directly?

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

async function main() {
  foo = await someOtherAsyncFunc();
  console.log(foo);
}
main()

或:

(async function() {
  foo = await someOtherAsyncFunc();
  console.log(foo);
})();

或:

(async () => {
  foo = await someOtherAsyncFunc();
  console.log(foo);
})();

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

这行得通 - 但我想更多地了解其背后的原因:我已经习惯了无法直接从顶层使用 await。然而,我也习惯于不得不调用一些特殊的库函数来真正从顶层“冒险”进入异步。在 Python 中,例如参见 [​​=21=]。要求 await 在异步函数中有什么意义 - 如果我可以从顶层调用任何异步函数?为什么 await 也不能在顶层使用?

Top-level await used 不是问题,但现在在 ES6 模块中是可能的。

为什么 top-level await 过去不是,现在仍然不是模块之外的一个原因是它可能允许语法歧义。 在模块之外。如果 non-module 脚本允许 top-level await,那么,缺少 re-working 规范(并破坏向后兼容性),在某些情况下解析器无法确定特定实例是否await 是一个变量名,或者被用作等待 right-hand 端的 Promise 解析的语法。

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

Module scrips允许top-level await(现在),因为它们一直禁止使用await作为标识符,所以不存在语法歧义。

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

Why doesn't it just return a Promise which is never executed because it doesn't get awaited?

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

Hanging Promises 在句法上是允许的 - 解析为 Promises 但不与其他地方交互的值。 (这是有道理的 - every .then or .catch 产生一个新的 Promise。如果每个 Promise 都必须被其他东西使用,你最终会得到一个无限倒退。)

正在做

(async () => {
  foo = await someOtherAsyncFunc();
  console.log(foo);
})();

本质上是

的语法糖
someOtherAsyncFunc()
  .then((foo) => {
    console.log(foo);
  });

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