JavaScript Promises Explained for Beginners
As JavaScript applications became more complex, handling asynchronous operations using callbacks started creating messy, hard-to-maintain code.
This is where Promises come in.
They provide a cleaner and more structured way to handle asynchronous operations.
πΉ What Problem Do Promises Solve?
π¨ Callback Hell
getUser(function(user) {
getOrders(user.id, function(orders) {
getOrderDetails(orders[0], function(details) {
console.log(details);
});
});
});
β Deep nesting β Hard to read β Difficult to debug
β With Promises
getUser()
.then(user => getOrders(user.id))
.then(orders => getOrderDetails(orders[0]))
.then(details => console.log(details))
.catch(err => console.error(err));
β Flat structure β Better readability β Easier error handling
πΉ What is a Promise?
π A Promise is a placeholder for a value that will be available in the future.
Think of it like:
"I donβt have the data right now, but I promise Iβll give it to you later."
πΉ Promise States
A promise has 3 states:
Pending
Initial state
Operation not completed yet
Fulfilled
Operation successful
Value is available
Rejected
Operation failed
Error is returned
π Example
const promise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve("Data fetched");
} else {
reject("Error occurred");
}
});
πΉ Basic Promise Lifecycle
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Done!");
}, 2000);
});
promise
.then(result => console.log(result)) // success
.catch(error => console.error(error)) // failure
.finally(() => console.log("Finished"));
π Flow
Promise starts β Pending
After 2 sec β Fulfilled
.then()runs.finally()always runs
πΉ Handling Success and Failure
fetchData()
.then(data => {
console.log("Success:", data);
})
.catch(error => {
console.log("Error:", error);
});
β .then() β handles success β .catch() β handles errors
πΉ Promise Chaining
Promises allow sequential execution without nesting.
getUser()
.then(user => getOrders(user.id))
.then(orders => getOrdersDetails(orders))
.then(details => console.log(details))
.catch(err => console.error(err));
π Each .then() returns a new promise
π₯ Why Chaining Works
Each step waits for the previous one
No pyramid structure
Cleaner and more readable
πΉ Real-World Example
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
πΉ Promises vs Callbacks
| Feature | Callbacks | Promises |
|---|---|---|
| Structure | Nested | Flat (chained) |
| Readability | Poor | Good |
| Error Handling | Manual | Centralized (catch) |
| Maintainability | Difficult | Easier |
πΉ Mental Model
Promise = future value
.then()= "When it's ready, do this".catch()= "If it fails, handle it"
πΉ Common Mistakes
β Not Returning Promise in Chain
getUser()
.then(user => {
getOrders(user.id); // β missing return
})
.then(orders => console.log(orders)); // undefined
β Always return the promise
β Multiple .then without Chain
promise.then(a => console.log(a));
promise.then(b => console.log(b));
π Runs independently (not sequential)
π Why Promises Matter
Foundation of modern async JavaScript
Used in:
APIs (
fetch)Databases
File systems
Base for async/await