Promises
A Promise represents a value that will be available later — the result of a network request, a timer or a file read.
On this page · 5 min · Intermediate
On this page
- Learning objectives
- Explanation
- Visual explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Intermediate
- Updated
- Oct 1, 2026
Related tutorials
Learning objectives#
- Describe the three states of a promise
- Consume promises with then, catch and finally
- Chain asynchronous steps
- Run tasks in parallel with Promise.all and Promise.allSettled
Explanation#
A promise starts pending. It then settles exactly once: fulfilled with a value, or rejected with an error.
.then() registers what to do with the value and returns a new promise, which is why calls can be chained. .catch() handles any rejection earlier in the chain. .finally() runs either way.
Promise.all() waits for several promises in parallel and rejects as soon as any one fails. Promise.allSettled() waits for all of them and reports each outcome.
Visual explanation#
Syntax#
const p = new Promise((resolve, reject) => { /* … */ });
p.then(value => …).catch(error => …).finally(() => …);
Code example: Simulating an API call#
function fetchUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) resolve({ id, name: 'Asha' });
else reject(new Error('Invalid user id'));
}, 300);
});
}
fetchUser(1)
.then(user => {
console.log('Loaded:', user.name);
return user.id * 10;
})
.then(points => console.log('Points:', points))
.catch(err => console.log('Error:', err.message))
.finally(() => console.log('Done'));
fetchUser(-1).catch(err => console.log('Error:', err.message));
Loaded: Asha Points: 10 Done Error: Invalid user id
Step-by-step explanation#
- fetchUser returns a promise that settles after 300ms.
- A positive id resolves with a user object; otherwise it rejects with an Error.
- The first then logs the name and returns a number, which becomes the input to the next then.
- catch handles a rejection from any earlier step. finally always runs.
- The second call rejects, so only its catch runs.
Real-world use case#
fetch() returns a promise. So do most database drivers, file APIs and SDKs, so promises are the foundation of nearly all real-world async JavaScript.
Common mistakes#
If you start another async call in then without returning it, the next then runs immediately with undefined.
Every promise chain should end with catch (or be awaited inside try/catch). Unhandled rejections can crash Node.js processes.
Best practices#
- Always return promises from then callbacks
- End chains with catch
- Reject with Error objects, not strings
- Use Promise.all for independent tasks instead of awaiting them one by one
Remember this#
A promise = a future value: pending → fulfilled or rejected.
.then for success, .catch for errors.
Promise.all waits for many at once.
Practice exercise#
Your task: Use Promise.all to load users 1, 2 and 3 in parallel with fetchUser and log all their names.
Show solution
Promise.all([fetchUser(1), fetchUser(2), fetchUser(3)])
.then(users => console.log(users.map(u => u.name)))
.catch(err => console.log('One failed:', err.message));
Mini quiz#
Which is NOT a promise state?
Want more? Practise all JavaScript MCQs · JavaScript interview questions
My notes#
Saved in this browser.