Explain the different states of a Promise
TL;DR
A Promise has three mutually exclusive states:
- Pending: It has not fulfilled or rejected yet.
- Fulfilled: It completed with a value.
- Rejected: It completed with a reason, conventionally an
Error.
Fulfilled and rejected Promises are settled. Once settled, a Promise cannot change state; later attempts to fulfill or reject it are ignored. “Resolved” is not always synonymous with “fulfilled”: a Promise can be resolved to another still-pending Promise and adopt its eventual state.
Promise state transitions
A promise begins pending and can settle exactly once into one of two terminal states.
“Resolved” is broader than “fulfilled”: resolving with another pending promise locks in adoption of that promise while the outer promise can remain pending.
Observe the state transition
JavaScript does not expose a synchronous promise.state property. You observe the outcome by attaching handlers:
The executor runs synchronously while the Promise is constructed. The Promise remains pending until the timer task calls resolve; its .then() reaction then runs as a microtask.
Pending
A pending Promise may eventually fulfill, reject, or remain pending forever. A common accidental forever-pending Promise forgets to call either callback on one control-flow branch.
Fulfilled
Fulfillment carries a value, including undefined when no value is supplied:
Rejected
Rejection carries a reason. Reject with an Error so callers receive a useful message and stack:
Attach a rejection handler or propagate the Promise to a caller that will. An unhandled rejection can be reported by the browser or terminate a Node.js process depending on runtime policy.
Settling happens once
Only the first settlement attempt has an effect:
This guarantee makes callbacks easier to compose, but application code should still clean up timers, listeners, or requests that are no longer needed; settling a Promise does not automatically cancel the underlying operation.