JavaScript Concurrency: Promise States
Welcome to the Promise States lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
So far, we've seen fulfilled and rejected promises.
>
Promise.resolve('ok');Async Result:
{fulfilled: 'ok'}>
Promise.reject('oh no');Async Result:
{rejected: 'oh no'}We also know that promises can take time to fulfill.
>
new Promise(resolve => {console.log('setting timer');setTimeout(() => resolve(), 1000);}).then(() => {console.log('fulfilled');});async console outputFor the first 1000 or so milliseconds before it was fulfilled, the promise above was in a state we haven't discussed yet. That state is "pending". Promises are initially created in the pending state, and can then be fulfilled with a value or rejected with a reason.
If you create a pending promise directly in your browser's console, you'll see something like this:
>
new Promise(resolve => { /* don't call resolve */ });Result:
Unlike fulfilled and rejected promises, Execute Program has no way to directly show a pending promise. (Also, this is the only lesson in the course where it would be useful!)
However, with a bit of instrumentation we can observe a pending promise indirectly. Here's an example that tracks a promise's state over time. It does this by using a
statevariable to record the state in thestateHistoryarray after every second.>
const stateHistory = [];let state = 'pending';let resolve;// Create a promise and store its resolve function.new Promise(r => { resolve = r; }).then(() => {state = 'fulfilled';});// Resolve the promise after 1.5 secondssetTimeout(resolve, 1500);// Check the promise's state once per second.setTimeout(() => { stateHistory.push(state); }, 0);setTimeout(() => { stateHistory.push(state); }, 1000);setTimeout(() => { stateHistory.push(state); }, 2000);stateHistory;Async Result:
['pending', 'pending', 'fulfilled']
In an earlier lesson, we saw one reason
Promise.resolveisn't calledPromise.fulfill: it can also create rejected promises. The next example shows another example of this: we usePromise.resolveto create a promise that's pending for about a second, and then rejects. It's never fulfilled at any point!>
Promise.resolve(new Promise(resolve => setTimeout(resolve, 1000)).then(() => {throw new Error('it failed');}));Async Result:
{rejected: 'Error: it failed'}Let's summarize what we've learned about promise states so far:
- A promise can be pending, fulfilled with a value, or rejected with a reason.
- Pending promises can become fulfilled or rejected.
- Once a promise is fulfilled or rejected, it stays in that state forever.
In real-world discussion of promises, it's common for people to say "resolved" when they mean "fulfilled". For example: "the promise resolved with the value 5."
But, "resolved" isn't actually a promise state. The
resolvemethod creates a new promise from the value we pass in. When we pass it a non-promise argument intoresolve, it creates a fulfilled promise. However, if we pass in a rejected promise, the new promise will also reject.>
const rejectedPromise = Promise.reject('rejection reason');Promise.resolve(rejectedPromise);Async Result:
{rejected: 'rejection reason'}In this course, we've been careful to avoid saying "resolved" when we mean "fulfilled". Although this is a relatively harmless error once you understand the difference, mixing the two terms up can lead to confusion.