JS Promises
What Is a Promise
A Promise is an object representing the eventual result of an operation that hasn't finished yet, starting in a pending state, and eventually settling into either fulfilled, meaning it succeeded, or rejected, meaning it failed.
Note: Think of a promise's three states as a package's shipping status, pending means still in transit, fulfilled means delivered, rejected means lost.
Warning: A promise can only settle once, either fulfilled or rejected, never both, and its state can never change again after settling.
Example: What Is a Promise
const promise = new Promise((resolve, reject) => {
resolve("Success!");
});
console.log(promise); // Promise {<fulfilled>: 'Success!'}
then, catch, and finally
.then() runs a function when a promise successfully fulfills, .catch() runs a function when a promise rejects, and .finally() runs a function regardless of whether the promise succeeded or failed.
Note: .finally() is a great place for cleanup logic, like hiding a loading spinner, since it runs no matter how the promise settles.
Warning: Skipping .catch() entirely means errors go unhandled, which can produce confusing, silent failures in your application.
Example: then, catch, and finally
const promise = new Promise((resolve) => resolve("Done"));
promise
.then(result => console.log(result))
.catch(err => console.log(err))
.finally(() => console.log("Finished"));
Chaining Promises
Multiple .then() calls can be chained together, with each one receiving the value returned by the previous one, letting you express a sequence of asynchronous steps in a clean, readable, top-to-bottom order.
Note: Returning a value from inside a .then() automatically passes that value along to the next .then() in the chain.
Warning: Forgetting to return a value from inside a .then() callback causes the next step in the chain to receive undefined instead of the expected data.
Example: Chaining Promises
Promise.resolve(1)
.then(n => n + 1)
.then(n => n * 2)
.then(result => console.log(result)); // 4
Promise.all
Promise.all() takes an array of promises and returns a single new promise that fulfills once every one of them has fulfilled, with an array of all their results, or rejects immediately if any single one rejects.
Note: Promise.all() is ideal when you need several independent operations to all finish before continuing, like loading multiple resources together.
Warning: If even one promise passed to Promise.all() rejects, the entire combined promise rejects immediately, even if the others would have succeeded.
Example: Promise.all
Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
]).then(results => console.log(results)); // [1, 2, 3]
Promise.race
Promise.race() takes an array of promises and settles as soon as the very first one settles, whether it fulfills or rejects, effectively racing them against each other and returning the fastest outcome.
Note: Promise.race() is a common technique for implementing a timeout, racing a real operation against a promise that rejects after a set delay.
Warning: Promise.race() settles based on speed alone, it doesn't wait to confirm whether a faster rejection was actually less important than a slower success.
Example: Promise.race
Promise.race([
new Promise(resolve => setTimeout(() => resolve("slow"), 100)),
new Promise(resolve => setTimeout(() => resolve("fast"), 10)),
]).then(result => console.log(result)); // "fast"
- Forgetting to add a .catch() to handle errors, an unhandled promise rejection can silently fail or clutter the console with warnings.
- Nesting .then() calls deeply instead of chaining them, which quickly becomes hard to read compared to a flat chain.
- Assuming a promise resolves immediately, code after creating a promise runs before its result is ready, that's the entire point of using one.
- A promise represents a value that will be available later, existing in one of three states: pending, fulfilled, or rejected.
- .then() handles a successful result, .catch() handles an error, and .finally() runs regardless of the outcome.
- Promise.all() waits for multiple promises to finish together, and Promise.race() resolves as soon as the first one finishes.
Promises have been supported in all major browsers since 2015 and are a completely standard part of modern JavaScript.
Chapter Quiz — Complete all 26 topics to unlock
0/26 topics done
Complete these topics first:
- JS Dates
- JS Math
- JS Conditionals
- JS Switch
- JS Loop For
- JS Loop While
- JS Iterables
- JS Sets
- JS Maps
- JS typeof
- JS Type Conversion
- JS Destructuring
- JS Arrow Functions
- JS Classes
- JS Modules
- JS Promises
- JS Async/Await
- JS DOM
- JS DOM Methods
- JS Events Advanced
- JS DOM Navigation
- JS DOM Collections
- JS Async Callbacks
- JS Async Parallel
- JS Date Set
- JS Set Logic