The Promise then() Function in JavaScript

Sep 11, 2019

Promises in JavaScript are an object representation of an asynchronous computation. You can think of a promise as a placeholder for a value that hasn't been computed yet. However, there's no way to get a promise's value from the promise directly - you need to call the then() function to register a callback that JavaScript will call when the value is computed.

// Create a promise that is immediately fulfilled with value 42.
const promise = Promise.resolve(42);

promise.then(value => {
  value; // 42
});

The then() Function's Parameters

The then() function takes 2 callback function parameters:

Recall that a promise is a state machine with 3 states:

  1. Pending The operation is in progress.
  2. Fulfilled The operation completed successfully.
  3. Rejected The operation experienced an error.

A promise always starts out in the pending state. If the promise transitions to the fulfilled state, JavaScript calls the onFulfilled() function. If you call then() on a promise that is already fulfilled, JavaScript will immediately call onFulfilled().

const promise = new Promise(function executor(resolve, reject) {
  // Fulfill the promise with value '42' after 100 ms.
  setTimeout(() => resolve(42), 100);
});

promise.then(value => {
  value; // 42
});

If the promise transitions to the rejected state, or if you call then() on a promise that is already rejected, JavaScript calls onRejected().

// Create a promise that is immediately rejected with an error object
const promise = Promise.reject(new Error('Oops!'));

promise.then(null, err => {
  err.message; // 'Oops!'
});

Both onFulfilled() and onRejected() are optional. If onFulfilled() is null like in the above example, JavaScript will do nothing if the promise is fulfilled. If you call .then() without an onRejected() function and the promise rejects, that will lead to an unhandled rejection error message.

then() vs catch()

The Promise#catch() function in JavaScript is a convenient shorthand for .then(). Calling .catch(onRejected) is syntactic sugar for .then(null, onRejected).

// Create a promise that is immediately rejected with an error object
const promise = Promise.reject(new Error('Oops!'));

// Equivalent to `.then(null, onRejected)`
promise.catch(function onRejected() {
  err.message; // 'Oops!'
});

Although .catch() isn't complicated under the hood, the name catch is valuable because you can think of .catch() as the promise analog to the catch part of try/catch. When you're scanning promise based code, seeing .catch() makes it easy to identify error handling.

Chaining

Promise chaining is one of the key reasons why promises are so useful. The then() function returns a promise p, and if your onFulfilled() function returns a promise q, p will adopt the state of q.

// Create a promise that is immediately rejected with an error object
const promise = Promise.reject(new Error('Oops!'));

// Equivalent to `.then(null, onRejected)`
promise.catch(function onRejected() {
  err.message; // 'Oops!'
});

Because of promise chaining, you don't need to catch errors in each individual then(). If you put catch() at the end of your promise chain, any errors in the promise chain will bypass the rest of the promise chain and go straight to your catch() error handler.

Promise.resolve(1).
  then(() => Promise.resolve(2)).
  then(() => Promise.reject(new Error('Oops!'))).
  then(() => console.log('This will not print')).
  catch(function errorHandler(err) {
    err.message; // 'Oops!'
  });

More Fundamentals Tutorials