π€ Welcome to the first article in my JavaScript ES2025 features series!
In this article, weβll explore one of the most anticipated additions β Top-Level await
. It's a powerful upgrade that makes working with asynchronous code in JavaScript simpler and cleaner, especially inside ES modules.
π What Is Top-Level await
in JavaScript?
In modern JavaScript, we typically use the async/await
combo to handle asynchronous code. Until now, await
could only be used inside an async function.
Traditional Way:
const fetchData = async () => {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
};
fetchData();
With Top-Level await:
Now, with Top-Level await
, you can skip the async function wrapper and use await
directly β at the top level of your JavaScript module.
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
β Cleaner. Simpler. Easier to read.
π Where Can You Use Top-Level await ?
Top-Level await
only works inside ES modules, which means:
Your file must use the
.mjs
extension orYour project must include
"type": "module"
inpackage.json
(for Node.js)Or you're using a
<script type="module">
tag in the browser
<script type="module">
const response = await fetch('/config.json');
const config = await response.json();
console.log(config);
</script>
π Can You Use Try/Catch?
Absolutely. Error handling with Top-Level await
works just like you'd expect:
try {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
} catch (err) {
console.error("Error fetching data:", err);
}
π§ How Top-Level await
Works Under the Hood
Although youβre writing plain await
at the top level, the JavaScript engine treats it like an async function.
(async () => {
const response = await fetch("https://api.example.com");
})();
So yes β it's still async! But now, your entire module behaves like an async function, which means:
The code execution pauses at each top-level await
Other modules importing this module will wait until it finishes
π Real-World Use Case
A common scenario: You want to load a config file before initializing your app.
config.js
const res = await fetch('/config.json');
export const config = await res.json();
main.js
import { config } from './config.js';
console.log("Starting app with config:", config);
// app starts here...
This is perfect for loading runtime data like environment variables, feature flags, or user session info.
β
Advantages of Top-Level await
π‘ *Cleaner Syntax *β No need to wrap logic inside async functions
π Better Flow Control β Pause execution until data is ready
π Improved Readability β Makes async code look like sync
β Disadvantages of Top-Level await
π Slower Module Loading β All importing modules must wait
π¦ *ESM-Only *β Doesn't work in CommonJS (require)
π§± Blocked Execution β Overusing it can hurt performance
π― Final Thoughts
Top-Level await
is one of the most practical features in ES2025 β it simplifies code, improves structure, and helps you better control async flow. Just make sure to use it where it makes sense, especially in bootstrapping or initialization logic.
Thanks for reading! π
If you found this useful, feel free to share it or drop your thoughts in the comments!
π Connect with me on LinkedIn: linkedin.com/in/parul-verma-pv14
π Stay tuned β more exciting ES2025 features coming up soon!
Top comments (0)