【发布时间】:2021-08-27 13:46:37
【问题描述】:
在 14.3.0 中通过--experimental-top-level-await 和后来的--harmony-top-level-await 向 Node.js 添加了顶级等待支持。
问题
如果当前 Node.js 运行时支持,我需要在我的 ESM 脚本文件中使用顶级 await。此外,我需要设置一个布尔标志来指示承诺已在顶层成功等待。
我的意思的一个例子:
let topLevelAwaitEnabled;
try {
await Promise.resolve(); // replaced with an actual promise
topLevelAwaitEnabled = true;
} catch (ignored) {
topLevelAwaitEnabled = false;
}
console.log(topLevelAwaitEnabled);
// carry on with the rest of the application, regardless of success or failure
// at some point, topLevelAwaitEnabled is checked to conditionally execute some code
如果启用顶级等待支持,则成功。 然而,如果不支持,这将在解析期间导致以下错误,并且无法在运行时用try/捕获catch:
$ node test.js...\test.js:3
await Promise.resolve(); // replaced with an actual promise
^^^^^
SyntaxError: await is only valid in async function
所以问题是:我如何使用顶级等待如果支持它,而不会与不支持顶级等待的 Node.js 运行时产生不兼容问题(要么没有 CLI 标志指定或根本没有运行时支持)?
如果答案是“不可能”,我想解释一下为什么这是不可能的。
在我实际提交XY problem 的情况下,根本问题是我需要顶级动态导入。
注意:我很清楚出于各种原因不建议使用顶级 await,但它对于我的应用程序的特定功能至关重要,并且不会对我的用例造成任何问题.替代品可能不够用。
尝试
我尝试了以下方法,均无效:
-
eval:我尝试将 await 行替换为eval("await Promise.resolve()"),希望在当前上下文中对代码进行评估。不幸的是,即使支持顶级 await,这也会导致相同的错误,因为它似乎没有继承当前上下文。 -
vm.compileFunction:同样的问题是eval(),不支持顶级等待。 -
vm.SourceTextModule:评估是异步的,需要在顶层等待以检查它是否受支持......这是一个问题 22。 - 基于
process.version和process.execArgv的await条件执行:解析过程中的错误 - 它从未真正执行代码,因此排除了条件执行。
【问题讨论】:
-
这里有你不使用 .then 的原因吗?如果您说问题是因为您需要顶级动态导入,那么似乎 then 而不是 await 会起作用,不是吗?
-
@ChaimFriedman 我正在实现一个 ESM loader polyfill,它可以动态导入其他 ESM 加载器以模拟 ESM 加载器链接 (not currently supported)。不幸的是,
getGlobalPreloadCode()钩子不是异步的,它会在我的脚本加载后立即调用。由于动态导入是异步的,我无法委托getGlobalPreloadCode()调用其他 ESM 加载器,因为它们尚未加载。剩下的钩子是异步的,我可以在钩子里面等待。
标签: node.js async-await top-level-await