Fundamentals of Promises
Learn more about JavaScript promises, a promise's lifecycle, and each of its states.
We'll cover the following
Introduction
While promises are often associated with asynchronous operations, they are simply placeholders for values. The value may already be known or, more commonly, it may be the result of an asynchronous operation. Instead of subscribing to an event or passing a callback to a function, a function can return a promise like this:
// fetch() promises to complete at some point in the futureconst promise = fetch("books.json");
The fetch()
function is a common utility function in JavaScript runtimes that makes network requests. The call to fetch()
doesn’t actually complete a network request immediately; that will happen later. Instead, the function returns a promise
object (stored in the promise
variable in this example, but we can name it whatever we want) representing the asynchronous operation so we can work with it in the future. Exactly when we’ll be able to work with that result depends entirely on how the promise’s lifecycle plays out.
The promise lifecycle
Each promise goes through a short lifecycle, starting in the pending state that indicates that the promise hasn’t been completed yet. A pending promise is considered unsettled. The promise in the previous example is in the pending state as soon as the fetch()
function returns it. Once the promise completes, it is considered settled and enters one of two possible states (see the figure below):
- Fulfilled: The promise has been completed successfully.
- Rejected: The promise didn’t complete successfully due to either an error or some other cause.
An internal [[PromiseState]]
property is set to pending
, fulfilled
, or rejected
to reflect the promise’s state. This property isn’t exposed on promise
objects, so we can’t determine which state the promise is in programmatically. But we can take a specific action when a promise changes states by using the then()
method.