What is a Promise in JavaScript?
Learn what a JavaScript Promise is, its pending, fulfilled, and rejected states, chaining with then/catch, and how it relates to async/await.
Expected Interview Answer
A Promise is an object representing the eventual result of an asynchronous operation, existing in one of three states: pending, fulfilled, or rejected. It lets you attach callbacks with .then() and .catch() instead of nesting callbacks directly, making async code easier to read and chain.
A Promise starts in the pending state and transitions exactly once to either fulfilled, with a resolved value, or rejected, with a reason for failure. Once settled, a Promise's state and value are immutable, so attaching a .then() later always sees the same outcome. Promises support chaining, where each .then() returns a new Promise, allowing sequential asynchronous steps to be composed cleanly and errors to propagate down the chain to a single .catch(). Utility methods like Promise.all, Promise.race, and Promise.allSettled coordinate multiple promises running concurrently, and async/await is syntactic sugar built directly on top of the Promise mechanism.
- Avoids deeply nested callback pyramids
- Provides a single place to handle errors with .catch()
- Composable via chaining and combinators like Promise.all
- Foundation for async/await syntax
- Guarantees a settled state is immutable once reached
AI Mentor Explanation
A Promise is like a DRS review sent upstairs to the third umpire — while it's pending, play pauses and everyone waits for a verdict. Once the decision comes back it settles permanently as either 'out' or 'not out', and that ruling never flips again no matter how many times the replay is rewatched. Commentators can queue up their reaction ahead of time, ready to fire the moment the verdict lands.
Promise state machine: pending to fulfilled or rejected
Pending
- Initial state
- Operation still in progress
- No value or reason yet
Fulfilled
- Transitioned once from pending
- Holds a resolved value
- .then() callbacks fire
Rejected
- Transitioned once from pending
- Holds a rejection reason
- .catch() callbacks fire
Step-by-Step Explanation
Step 1
Create the Promise
new Promise((resolve, reject) => {...}) starts execution immediately in the pending state.
Step 2
Async work runs
The executor function performs the asynchronous operation, such as a network call or timer.
Step 3
Settle once
Calling resolve(value) or reject(reason) transitions the Promise to fulfilled or rejected exactly one time.
Step 4
Attach handlers
.then() registers a fulfillment handler and .catch() registers a rejection handler, queued as microtasks.
Step 5
Chain results
Each .then() returns a new Promise, letting you compose multiple async steps sequentially.
What Interviewer Expects
- Names all three Promise states accurately
- Explains that a settled Promise is immutable
- Knows the difference between .then/.catch and async/await
- Can describe Promise.all vs Promise.race behavior
- Understands Promises resolve via the microtask queue
Common Mistakes
- Saying a Promise can change state after settling
- Confusing a Promise with the value it eventually holds
- Forgetting to add a .catch() and missing unhandled rejections
- Believing Promises run synchronously
- Not knowing async/await is built on top of Promises
Best Answer (HR Friendly)
“A Promise is a placeholder for a value that isn't ready yet, like a receipt for an order that's still being processed. It lets code react once that value is finally ready or if something goes wrong, instead of freezing everything while waiting.”
Code Example
function fetchUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) resolve({ id, name: 'SkillVeris User' });
else reject(new Error('Invalid id'));
}, 100);
});
}
fetchUser(1)
.then((user) => {
console.log(user.name); // SkillVeris User
return user.id;
})
.then((id) => console.log('ID:', id)) // ID: 1
.catch((err) => console.log(err.message));Follow-up Questions
- What is the difference between Promise.all and Promise.allSettled?
- How does async/await relate to Promises under the hood?
- What happens to an unhandled Promise rejection?
- How does the microtask queue relate to Promise resolution timing?
- How would you implement a simple Promise-based retry function?
MCQ Practice
1. How many times can a Promise transition state after being created?
A Promise transitions from pending to either fulfilled or rejected exactly once, and remains immutable afterward.
2. Which method rejects if any one of the given promises rejects, but resolves with all values otherwise?
Promise.all resolves with an array of all values only if every promise fulfills, and rejects immediately if any one rejects.
3. Where are .then() callbacks queued for execution?
.then() and .catch() callbacks are scheduled on the microtask queue, which runs before the next macrotask.
Flash Cards
What are the three states of a Promise? — Pending, fulfilled, and rejected.
Can a settled Promise change state? — No, once fulfilled or rejected, it is permanently immutable.
What does .then() return? — A new Promise, enabling chaining of sequential async steps.
How does async/await relate to Promises? — It is syntactic sugar over Promises, letting you write async code that reads like synchronous code.