node.jsasync-awaittop-level-await

Use a top-level await, if supported by the current runtime


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.

The Problem

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.

Attempts

I have tried the following methods, to no avail:


Solution

  • 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.