"I don't get Promises" β Every beginner at least once.
This is your ultimate guide to understanding JavaScript Promises from scratch, with real-life analogies, live examples, and step-by-step breakdowns.
π Real-Life Analogy: Ordering Pizza
Imagine this:
- You order a pizza π.
- The restaurant says: "We'll deliver it in 30 minutes."
- You're now waiting β this is like an asynchronous task.
- When the pizza arrives, you eat = β _ Success_
- If they mess up, no pizza = β Failure
JavaScript Promises work just like that. You're not blocking your whole evening waiting β you can keep watching your show while the delivery happens in the background.
π€ What Is a Promise?
A Promise is a JavaScript object that represents an action that hasnβt finished yet but will finish in the future. It can result in:
- Resolved (success)
- Rejected (failure)
- Pending (still waiting)
Why Promises?
Traditionally, we handled async actions with callbacks. But callbacks quickly become hard to manage, especially if you have to chain multiple async actions.
Promises help you:
- Write cleaner code
- Chain operations easily
- Handle errors in one place
Basic Syntax:
let promise = new Promise(function(resolve, reject) {
// async task
});
resolve()
means success,reject()
means failure.
π¦ Example 1: Creating Your First Promise
let pizzaOrder = new Promise(function(resolve, reject) {
let pizzaReady = true; // Try changing this to false
if (pizzaReady) {
resolve("Your pizza is here!");
} else {
reject("Sorry, pizza shop is closed.");
}
});
You now have a Promise object. But how do you use it?
Using .then()
and .catch()
:
pizzaOrder
.then(function(result) {
console.log("Success:", result);
})
.catch(function(error) {
console.log("Error:", error);
});
π .then()
β Handling Success
.then()
is a method that runs when a Promise is resolved. Think of it as "what to do next if things go right."
promise.then((value) => {
console.log("Resolved with:", value);
});
- It takes one argument: a callback function
- That function receives the result of resolve()
π₯ .catch()
β Handling Errors
.catch()
is a method that runs when a Promise is rejected. It's like a dedicated error handler.
promise.catch((error) => {
console.error("Something went wrong:", error);
});
- Helps prevent your app from crashing
- Use it at the end of your chain to capture any error from the previous steps
β
.finally()
β Always Runs
.finally()
runs whether the promise is resolved or rejected.
promise.finally(() => {
console.log("Cleanup, logging, or UI update.");
});
- Great for hiding loaders, resetting UI, logging
- Doesnβt receive any arguments
Full Flow Example:
pizzaOrder
.then((res) => console.log("β", res))
.catch((err) => console.log("β", err))
.finally(() => console.log("π¦ Order attempt finished"));
Live Example: Try it on JSFiddle - Basic Pizza Promise or paste into browser console.
π§οΈ How Promises Work Internally
NEW Promise
|
V
Pending ---> Resolved (Success)
\---> Rejected (Failure)
The Promise only resolves ONCE. Either resolve OR reject.
π§© States of a Promise
State | Description |
---|---|
Pending | Waiting for result (default state) |
Fulfilled | Operation completed successfully |
Rejected | Operation failed |
π Example 2: Chaining Promises
function stepOne() {
return new Promise((resolve) => {
setTimeout(() => resolve("Step 1 done"), 1000);
});
}
function stepTwo() {
return new Promise((resolve) => {
setTimeout(() => resolve("Step 2 done"), 1000);
});
}
stepOne()
.then((msg) => {
console.log(msg);
return stepTwo();
})
.then((msg) => {
console.log(msg);
})
.finally(() => {
console.log("All steps finished.");
});
Why Chaining Is Important:
Without chaining, each .then()
would run independently. With chaining, you ensure they run in sequence.
Live Example: Try it on JSFiddle - Promise Chaining
β οΈ Common Beginner Mistakes
1. Not returning a Promise inside .then()
.then(() => {
stepTwo(); // Not returned β won't wait for this
})
Correct:
.then(() => {
return stepTwo();
})
2. Handling success only and ignoring errors
Always use .catch()
to handle errors, or your app may crash silently.
3. Nested Promises (Anti-pattern)
stepOne().then(() => {
stepTwo().then(() => {
console.log("Done");
});
});
Better:
stepOne()
.then(() => stepTwo())
.then(() => console.log("Done"));
β¨ Async/Await β Clean Alternative to Promises
With async/await
, you can write asynchronous code that looks like synchronous code.
async function makePizza() {
try {
let msg1 = await stepOne();
console.log(msg1);
let msg2 = await stepTwo();
console.log(msg2);
} catch (error) {
console.log("Error:", error);
}
}
makePizza();
await
waits for the promise to resolve. You can only useawait
insideasync
functions.
Live Example: Try it on JSFiddle - Async/Await
π± Real API Call with Fetch + Promises
Let's now look at how Promises power real-world API calls with fetch()
.
Using .then() Chain:
fetch("https://jsonplaceholder.typicode.com/users/1")
.then((response) => response.json())
.then((user) => console.log(user))
.catch((error) => console.error("Error fetching:", error))
.finally(() => console.log("Request completed"));
Using async/await:
async function getUser() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const user = await response.json();
console.log(user);
} catch (error) {
console.log("Error:", error);
} finally {
console.log("Request completed");
}
}
getUser();
π§ͺ Whatβs Happening:
- The fetch call returns a Promise.
- If resolved, .then() gives you a Response object.
- .json() is another Promise to convert the stream into usable data.
- Any network or conversion failure goes to .catch().
π― Practice Challenge
Challenge: Write a function using async/await
that:
- Fetches posts from
https://jsonplaceholder.typicode.com/posts
- Logs the first 5 post titles
Solution:
async function getPosts() {
try {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
const posts = await res.json();
posts.slice(0, 5).forEach(post => console.log(post.title));
} catch (e) {
console.error("Error:", e);
} finally {
console.log("Finished fetching posts");
}
}
getPosts();
Feel free to customize it, chain multiple fetches, or try .then()
instead of async/await
to test your understanding.
π§ Final Thoughts
JavaScript Promises are one of the most powerful tools for handling asynchronous operations. Mastering them unlocks the ability to work with APIs, animations, timers, and all async logic like a pro.
Key Takeaways:
Promises have 3 states: Pending β Fulfilled or Rejected
-
.then()
is for success,.catch()
is for errors -
.finally()
always runs - Use
async/await
for cleaner syntax
β Next Steps:
- Build a fake food ordering app using chained Promises
- Refactor old callback-based code to Promises
- Explore
Promise.all()
andPromise.race()
If this helped you understand Promises better, please β€οΈ the post, drop a comment, or follow me for more beginner-friendly JavaScript tutorials!
Author: Lokesh Keswani
Follow me on Dev.to for more dev content.
Top comments (0)