Promise
A Promise is a special JavaScript object that represents the result of an asynchronous operation which may finish later, either successfully or with an error. Put simply, a Promise is a "promise" to deliver a result in the future: there is no answer right now, but there will be one when the operation completes.
Theory
TL;DR
- A Promise represents the future result of an asynchronous operation.
- States:
pending, then eitherfulfilledorrejected; the transition happens only once. resolve(value)moves it tofulfilled,reject(error)moves it torejected.- Handling the result:
.then(),.catch(),.finally(); each of them returns a new Promise. - Combinators:
Promise.all(),Promise.allSettled(),Promise.race(). async/awaitis syntactic sugar over Promises, not a separate mechanism.
Quick example
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Data received!');
}, 2000);
});
}
fetchData().then((data) => console.log(data));fetchData() returns a Promise: after 2 seconds it resolves and then() receives the result.
The three states of a Promise
| State | Description | Example |
|---|---|---|
| pending | waiting, the operation has not finished yet | the request is in flight |
| fulfilled | completed successfully, there is a result | the data arrived |
| rejected | rejected, an error happened | the server returned 404 |
Creating a Promise and handling the result
A Promise can be created by hand:
const promise = new Promise((resolve, reject) => {
const success = Math.random() > 0.5;
if (success) {
resolve('Success!');
} else {
reject('Error!');
}
});resolve(value)moves the Promise to the fulfilled state;reject(error)moves it to the rejected state.
The result is handled with a chain of methods:
promise
.then((result) => {
console.log('Result:', result);
})
.catch((error) => {
console.error('Error:', error);
})
.finally(() => {
console.log('Always runs');
});| Method | When it is called | What it returns |
|---|---|---|
.then() | on success (resolve) | a new Promise |
.catch() | on an error (reject) | a new Promise |
.finally() | in any case (success or error) | a new Promise |
An example with an error:
function fetchUser() {
return new Promise((_, reject) => {
setTimeout(() => reject('User not found'), 1000);
});
}
fetchUser()
.then(user => console.log(user))
.catch(err => console.error(err));Output:
User not foundPromise chaining
Every .then() returns a new Promise, so asynchronous actions can be lined up into a chain:
getUser()
.then(user => getPosts(user.id))
.then(posts => getComments(posts[0].id))
.then(comments => console.log(comments))
.catch(err => console.error('Error:', err));The advantage: no nesting, the code reads top to bottom, unlike callback hell.
For a value that is already available there is a short form:
Promise.resolve('OK').then(console.log); // "OK"
Promise.reject('Error').catch(console.error); // "Error"Parallel Promises
Promise.all() waits until all of them settle successfully
Promise.all([
fetch('/user'),
fetch('/posts'),
]).then(([userRes, postRes]) => {
console.log('Both responses received');
});If at least one Promise rejects, the whole all() becomes rejected.
Promise.allSettled() waits for all of them regardless of errors
Promise.allSettled([
fetch('/user'),
fetch('/wrong-url'),
]).then(console.log);The result:
[
{ status: "fulfilled", value: Response },
{ status: "rejected", reason: TypeError }
]Promise.race() returns the first one that settles
Promise.race([
fetch('/slow'),
fetch('/fast'),
]).then(console.log);Promises and async/await
Promises are the foundation the async/await syntax is built on:
async function main() {
try {
const user = await getUser();
const posts = await getPosts(user.id);
console.log(posts);
} catch (err) {
console.error(err);
}
}Here await simply waits for a Promise, but it makes the code linear and clear.
A simple analogy:
A Promise is like a pizza delivery. You place the order and the Promise is created in the
pendingstate. The courier is on the way, the operation is running. The courier arrives and the Promise resolves. The courier gets lost and the Promise rejects. You can subscribe to the result withthenand handle errors withcatch.
Summary
| Term | Description |
|---|---|
| Promise | An object representing the future result of an asynchronous operation |
| States | pending, then fulfilled or rejected |
| Methods | .then(), .catch(), .finally() |
| Main benefit | Simplifies asynchronous work and saves you from callback hell |
| Modern syntax | async/await is built on Promises |
Common mistakes
- Thinking a Promise can be re-resolved: after the first
resolveorrejectthe state is fixed forever and later calls are ignored. - Believing a Promise is lazy. The executor function starts immediately at
new Promise(...), before any.then(). - Forgetting
returninside.then(), so the next link receivesundefinedinstead of the data. - Putting
.catch()somewhere other than the end of the chain: errors from the following.then()handlers are then left unhandled. - Reaching for
Promise.all()wherePromise.allSettled()is needed: one failure discards the whole result even though the other requests already succeeded. - Confusing
Promise.race()withPromise.any():racereturns the first settled result even if it is an error, whileanywaits for the first successful one. - Wrapping a function that already returns a Promise into
new Promise: that is an extra layer and a source of swallowed errors.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.