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
async
function 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. -
await
pauses only the async function, not the entire JavaScript engine. - Use
try/catch
to 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.