A Promise in JavaScript is an object representing the eventual completion (or failure) of an asynchronous operation and its resulting value. Think of it like ordering food at a restaurant: you get a buzzer (the promise) that will eventually notify you when the meal is ready (success) or if they ran out of ingredients (failure).
1. The Three States of a Promise
A Promise is always in one of these three states:
- Pending: Initial state; the operation hasn’t finished yet.
- Fulfilled (Resolved): The operation completed successfully.
- Rejected: The operation failed.
2. Creating a Promise
You create a promise using the new Promise constructor. It takes a function (executor) with two arguments: resolve and reject.
JavaScript
const myPromise = new Promise((resolve, reject) => {
const success = true;
setTimeout(() => {
if (success) {
resolve("Data fetched successfully!");
} else {
reject("Error: Could not fetch data.");
}
}, 2000); // Simulating a 2-second network delay
});
3. Consuming a Promise
Once a promise is created, you need to handle the result using .then(), .catch(), and .finally().
- .then(): Runs when the promise is fulfilled.
- .catch(): Runs when the promise is rejected.
- .finally(): Runs regardless of the outcome (useful for cleanup).
JavaScript
myPromise
.then((data) => {
console.log(data); // "Data fetched successfully!"
})
.catch((error) => {
console.error(error); // "Error: Could not fetch data."
})
.finally(() => {
console.log("Operation finished.");
});
4. Chaining Promises
One of the biggest advantages of Promises is the ability to chain them. This avoids “Callback Hell” (nested, unreadable code).
fetchUser(1)
.then(user => fetchPosts(user.id))
.then(posts => fetchComments(posts[0].id))
.then(comments => console.log(comments))
.catch(err => console.error("Error in the chain:", err));
5. Why Use Promises? (The “Callback Hell” Solution)
Before Promises, developers used nested callbacks. If you had to do three things in a row, the code would “pyramid” to the right, making it unreadable.
Callback Hell (Old way):
JavaScript
getData(function(a) {
getMoreData(a, function(b) {
getEvenMoreData(b, function(c) {
console.log(c);
});
});
});
Promise Chaining (New way):
JavaScript
getData()
.then(a => getMoreData(a))
.then(b => getEvenMoreData(b))
.then(c => console.log(c))
.catch(err => console.log(err));
5. Modern Alternative: Async/Await
In modern JavaScript (ES8+), we use async and await to make asynchronous code look and behave like synchronous code. It is built on top of Promises.
JavaScript
async function displayData() {
try {
const data = await myPromise; // Waits for the promise to resolve
console.log(data);
} catch (error) {
console.error(error); // Handles rejection
}
}
displayData();
