Top-level await support was added to Node.js in 14.3.0 via --experimental-top-level-await
and later to --harmony-top-level-await
.
I need to use a top level await in my ESM script file, if it is supported by the current Node.js runtime. And further, I need to set a boolean flag to indicate that the promise was successfully awaited at the top level.
An example of what I mean:
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
If top level await support is enabled, this succeeds fine. However, if it is not supported, this will result in the following error during parsing and cannot be caught at runtime with a try
/catch
:
$ node test.js...\test.js:3
await Promise.resolve(); // replaced with an actual promise
^^^^^
SyntaxError: await is only valid in async function
So the question is: How can I use a top level await if it is supported, without creating incompatibility issues with Node.js runtimes that do not support top level await (either no CLI flag was specified or simply no runtime support)?
If the answer is "it is not possible", I would like an explanation as to why this is impossible.
In the case I am actually committing an XY problem, the underlying issue is I need a top-level dynamic import.
Note: I am well aware that top level await is not recommended for a variety of reasons, however it is crucial for a specific functionality of my application and does not impose any issue with my use case. Alternatives will likely not suffice.
I have tried the following methods, to no avail:
eval
: I have tried replacing the await line with an eval("await Promise.resolve()")
, in the hope the code was evaluated in the current context. Unfortunately, even if top level await is supported, this will result in the same error, as it does not seem to inherit the current context.vm.compileFunction
: Same issue was eval()
, top level await is not supported.vm.SourceTextModule
: Evaluation is asynchronous and would need to be awaited at the top level to check if it is supported... which is a catch 22.await
based on process.version
and process.execArgv
: The error during parsing - it never actually executes the code, so conditional execution is ruled out.As far as I know this is not possible because the parser will simply error out. The compiler will not understand the await
directive and will not complete its cycle. This is probably similar to using a word that's simply not a recognized keyword.
The closest you can get is using an anonymous function.