Promises, Async, and Await
Mastering asynchronous JavaScript can be tricky. This guide walks you through the problems callbacks introduce, how Promises help, and why async/await makes your code cleaner and more readable.
What Is async in JavaScript?
Problem: You want a function that always returns a Promise.
Solution: Prefix it with async.
- An
asyncfunction always returns a Promise. - If you return a non-Promise value, JavaScript wraps it in a resolved Promise.
async function getData() {
return "Hello World"; // Returns Promise.resolve("Hello World")
}
const dataPromise = getData();
console.log(dataPromise); // Promise {<fulfilled>: "Hello World"}
dataPromise.then(res => console.log(res)); // Hello World
If you return a Promise explicitly, it stays as is:
const p = new Promise(resolve => setTimeout(() => resolve("Delayed"), 2000));
async function getData() {
return p; // returns p unwrapped
}
getData().then(console.log); // after 2s logs "Delayed"
Handling Promises: .then() vs await
1. Using .then() (Old Way)
| Using .then() | |
|---|---|
2. Using async/await
| Using async/await | |
|---|---|
Behind the Scenes of await
When you await a Promise:
- The async function is suspended at that point.
- It’s removed from the call stack (the main thread is free).
- When the Promise resolves, the function resumes where it left off.
This prevents blocking the UI and keeps your app responsive.
Real-World Example: fetch
Problem: You need to fetch JSON data from an API.
const API_URL = "https://api.github.com/users/yourusername";
async function fetchUser() {
try {
const response = await fetch(API_URL); // 1. fetch() returns a Promise
const jsonValue = await response.json(); // 2. response.json() returns a Promise
console.log(jsonValue);
} catch (err) {
console.error("Error fetching user:", err);
}
}
fetchUser();
Key Points:
- Both
fetch()andresponse.json()return Promises. -
awaitpauses only the async function, not the entire JavaScript engine. - Use
try/catchto handle network or parsing errors.
Error Handling
1. try…catch inside an async function
async function safeFetch(url) {
try {
const res = await fetch(url);
const data = await res.json();
return data;
} catch (err) {
console.error("Fetch error:", err);
}
}
2. .catch() on the returned Promise
async function badFetch() {
const res = await fetch("https://invalid.url");
return res.json();
}
badFetch().catch(err => console.error("Caught:", err));
Quick Interview Tips
What is async?
Marks a function to always return a Promise.
What is await?
Pauses an async function until a Promise settles.
Why use async/await?
Cleaner syntax, easier error handling.
When not to use it?
For small one-off Promises or in environments without ES2017 support.
async/await vs .then()/.catch()
-
Syntax & Readability
.then(): chaining callbacks, can become nestedasync/await: flat, “top-to-bottom” flow
-
Error Handling
.catch(): single or per-chain handlerstry…catch: group multiple awaits or isolate individual calls
-
Sequential vs. Parallel
- Sequential by default in both (
await a; await b;) - Parallel with
Promise.all([…, …])
- Sequential by default in both (
-
Debugging & Stack Traces
.then(): anonymous callbacks in tracesasync/await: resembles sync code, easier breakpoints
-
When to Use
async/await: multiple dependent steps, cleaner logic, modern codebases.then()/.catch(): simple one-off Promises, existing promise-only libraries
Both patterns run on Promises; choose based on readability, error-handling style, and project needs. async/await is purely syntactic sugar.