How can I use async/await at the top level?
Go async at the top level by encapsulating your code within an Immediately-Invoked Function Expression (IIFE). This enables you to use await
right out the gate:
This pattern delivers a nifty way to use await
at the top level where native support is missing, without reworking your whole code structure.
Making async/await work at the top level
With the power of ECMAScript modules and certain JavaScript environments, top-level await bursts onto the scene, streamlining your async code:
This nifty feature can be accessed in Node.js v13.3+ with the --harmony-top-level-await
flag or from v14.8+ natively. Additionally, it is supported by TypeScript (v3.8+), Deno, and certain Webpack configurations.
Taming the error beast
Manage errors when using await
at the top level using a try/catch block:
Alternatively, a .catch()
appended to promises tidies up unhandled rejections:
Awakening compatibility with Node.js
To enable ESM syntax, including top-level await, in a Node.js project which relies on CommonJS, you can convert files to the .mjs
format or specify "type": "module"
in your package.json
:
Supercharging asynchronous execution
Prep your functions for easier use with await using Node.js's fabulous promisify utility. Your code readability will thank you for it:
Fetching HTTP requests with axios, in style
When getting data from an API, axios
pairs perfectly with top-level await, improving readability:
Using top-level await, you can say goodbye to chaining .then()
.
When scripts join forces
Concatenated Node.js scripts may lose their async nature. To handle this, consider creating a new async scope:
Pros & cons of top-level await
While top-level await makes async programming easier, be aware of the following trade-offs:
-
Pros:
- Code Readability: Asynchronous code that looks synchronous for the win!
- Efficient Loading: Dependencies follow the best sequence without extra code.
- Simpler Error Handling: Try/catch blocks can directly surround awaited calls.
-
Cons:
- Potential Performance Costs: Misuse could lead to unintentional stops in async flow.
- Import Caution: All importing modules will wait, possibly affecting startup time.
- Older Compatibility: Top-level await might not be available in older environments or toolchains.
Overcoming challenges
While implementing async/await
is beneficial, it presents some hurdles:
- Concatenated Files: Create a new async scope for your concatenated scripts.
- CommonJS patterns in Node.js: Refactor your code using esrun for TypeScript or use
.mjs
format while keeping traditional Node.js style.
Enhancements and final words
Couple more tips before you brave the async/await terrain:
- Debugging with Chrome DevTools, Node.js, or Safari Web Inspector supports top-level await.
- For a different flavor of async programming, try the object-oriented promise API.
- Always check compatibility of your specific environment before employing top-level await.
Was this article helpful?