Async/Await in JavaScript

Hello readers,
Welcome to another blog of JS. In the last blogs, we explored callbacks and promises — and honestly… things started getting messy
Callbacks gave us callback hell, and promises improved things… but chaining .then() still felt a bit unnatural.
So today, we’re solving that problem.
Let’s understand async/await — the cleanest way to write asynchronous code in JavaScript.
Why Async/Await?
Promises were powerful, but:
Too many
.then()chainsHarder to read for beginners
Error handling wasn’t very intuitive
Nested logic still looked confusing
For example:
fetchData()
.then(res => process(res))
.then(data => save(data))
.catch(err => console.log(err));
Looks good... but imagine 10 steps, hard to manage, right?
That's why Async/Await is introduced to make async code:
Look synchronous
Easier to read
Easier to debug
How does async work?
If you know that the task will be asynchronous, make the function async. To do this, simply write async before the function keyword, or in an arrow function, use the async keyword before the parentheses ().
Example:
async function getData() {
return "Hello";
}
//or in arrow function
const getData = async () => {
return "Hello";
}
And when you make a function async, then the function always returns a Promise, so you can also do this**:**
getData().then(console.log); // Hello
Even if you return a normal value → JS wraps it in a promise.
Await Keyword
await keyword does only one thing. It pauses execution until a promise resolves.
async function fetchUser() {
const response = await fetch("https://api.com/user");
const data = await response.json();
console.log(data);
}
Here:
JS waits for promise resolution
Then moves to the next line
Code looks synchronous, but is async internally
Error handling in async/await
With promises, we use catch like this:
fetchData()
.then(res => res.json())
.catch(err => console.log(err));
But, in async-await code, we use try/catch. Like this:
async function getData() {
try {
const res = await fetchData();
const data = await res.json();
console.log(data);
} catch (err) {
console.log(err);
}
}
This feels like a normal try/catch—much easier to understand.
I will write a separate blog on handling errors, so don't worry. Just follow me to get notifications.
Async/Await vs Promises
| Features | Promises | Async/Await |
|---|---|---|
| Syntax | .then() chaining |
Cleaner, synchronous style |
| Readability | Medium | High |
| Error Handling | .catch() |
try/catch |
| Debugging | Harder | Easier |
| Learning Curve | Moderate | Beginner-friendly |
Examples of Promise & async/await
I hope everything is clear so far, but if you still have any doubts, here is a real-life example. Write them yourself and try to understand the flow.
Ordering Food
Promises Way:
orderFood()
.then(cookFood)
.then(serveFood)
.then(eatFood)
.catch(handleError);
Async/Await Way:
async function enjoyFood() {
try {
const order = await orderFood();
const cooked = await cookFood(order);
const served = await serveFood(cooked);
await eatFood(served);
} catch (err) {
handleError(err);
}
}
When Should You Use Async/Await?
You want clean, readable code
You have sequential async steps
You need better error handling
You want code that looks synchronous
Avoid or be careful when:
You need parallel execution → use
Promise.allIn very small one-liners → promises are fine
That's it for this blog. I hope async/await, which is nothing but syntactical sugar now, makes sense to you. Now, you have completed this journey:
Callbacks → Promises → Async/Await
And honestly…
Async/await is where things finally start to feel natural.
In the next blog, we can dive deeper into handling the error in JS.
Until then...
Stay consistent and keep grinding.
Peace ✌️





