JavaScript Promise Chaining
Promise chaining is what makes promises meaningfully better than
callbacks.
The key idea is that a Promise's then()
function returns another promise, so you can chain .then()
calls together
to tell JavaScript to execute async calls in order.
const start = Date.now();
return Promise.resolve().
then(() => new Promise(resolve => setTimeout(resolve, 50))).
then(() => new Promise(resolve => setTimeout(resolve, 50))).
then(v => {
console.log(Date.now() - start); // About 100ms passed
});
Return Values
The first parameter to the then()
function is called onFulfilled()
.
That's because JavaScript calls that function when the promise is fulfilled.
JavaScript calls the onFulfilled()
function with the value the promise
was fulfilled with as the first parameter.
Promise chaining works because, if your onFulfilled()
function
returns a promise q
, the promise then()
returns will adopt the state of q
. So the promise then()
returns will have the same fulfilled value as q
.
return Promise.resolve(1).
// If `onFulfilled()` returns a promise, JavaScript calls the
// next `onFulfilled()` with the fulfilled value of the promise
// your `onFulfilled()` returned.
then(v => new Promise(resolve => setTimeout(() => resolve(v + 1), 10))).
then(v => new Promise(resolve => setTimeout(() => resolve(v + 1), 10))).
then(v => new Promise(resolve => setTimeout(() => resolve(v + 1), 10))).
// If `onFulfilled()` returns a value that isn't a promise,
// JavaScript calls the next `onFulfilled()` with that value.
then(v => v + 1).
then(v => {
console.log(v); // 5
});
Error Handling
Promise chaining also consolidates error handling. All you need is one
.catch()
function call at the end
of your promise chain to handle any errors that occur in your promise chain.
Promise.resolve(1).
then(v => v + 1).
// Async error in the middle of the chain goes straight
// to `catch()`.
then(() => Promise.reject(new Error('Oops'))).
then(v => v + 1).
catch(err => {
err.message; // 'Oops'
});
Promise.resolve(1).
then(v => v + 1).
// Sync error in the middle of the chain goes straight
// to `catch()` too.
then(() => { throw new Error('Oops'); }).
then(v => v + 1).
catch(err => {
err.message; // 'Oops'
});
Summary
The high level structure of a promise chain is a series of .then()
calls, each with an onFulfilled()
parameter, and a single .catch()
at the end. JavaScript executes the .then()
callbacks in order,
or goes straight to .catch()
if one of the onFulfilled()
functions errors out.