JavaScript Promises Explained Before You Learn async/await
Understand JavaScript Promises from scratch before diving into async/await. Learn what a Promise is, how .then() and .catch() work, and how to chain multiple async operations.
Before async/await existed, JavaScript Promises were the solution to callback hell. Even though async/await is now preferred, understanding Promises is essential — because async/await is built on top of them, and you’ll encounter them in documentation and older codebases constantly.
What Is a Promise?
A Promise represents a value that isn’t available yet but will be in the future. Think of it like ordering food at a restaurant — you get a ticket (the Promise) and eventually your food arrives (the value) or the kitchen runs out of ingredients (an error).
A Promise is always in one of three states:
- Pending — the operation is still running
- Fulfilled — it completed successfully
- Rejected — it failed
Creating a Promise
const myPromise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve("Data loaded!"); // Fulfilled
} else {
reject("Something failed"); // Rejected
}
});
In practice, you rarely create Promises manually — fetch(), database drivers, and many APIs return them automatically.
Consuming Promises with .then() and .catch()
fetch("https://api.github.com/users/kaikobud")
.then(response => response.json()) // runs on success
.then(data => {
console.log(data.name);
return data.public_repos; // pass value to next .then()
})
.then(repoCount => console.log(`Repos: ${repoCount}`))
.catch(error => console.error(error)) // runs on any failure
.finally(() => console.log("Done")); // always runs
Each .then() returns a new Promise, enabling chaining.
Promise.all — Run Multiple Promises in Parallel
const p1 = fetch("/api/users").then(r => r.json());
const p2 = fetch("/api/posts").then(r => r.json());
const p3 = fetch("/api/tags").then(r => r.json());
Promise.all([p1, p2, p3]).then(([users, posts, tags]) => {
console.log(users, posts, tags);
});
Promise.all waits for all promises to resolve. If any one rejects, the entire thing rejects.
Conclusion
JavaScript Promises are the foundation of all async JavaScript. Even if you prefer async/await (which you should), understanding how .then(), .catch(), and Promise.all() work makes you a much more effective developer. Every time you use await, there’s a Promise underneath.
Read next: async/await in JavaScript
External resource: MDN — Using Promises
Related Articles
async/await in JavaScript: Making Async Code Readable
Learn how async/await in JavaScript works with clear examples. Understand how it replaces Promise chains, handles errors with try/catch, and makes asynchronous code easier to read.
How to Write Clean Functions in JavaScript
Learn how to write clean JavaScript functions that are easy to read, test, and maintain. This guide covers naming, single responsibility, pure functions, and avoiding common pitfalls.
CSS Flexbox in Plain English: A Beginner's Guide
Learn CSS Flexbox with simple, visual explanations. This guide covers display flex, justify-content, align-items, flex-wrap, and practical layouts every developer needs to know.