This design pattern is useful for generating a sequence of asynchronous actions from a list of elements.

There are two variants :

The “then” reduction

This variant of the pattern builds a [.then()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then>) chain, and might be used for chaining animations, or making a sequence of dependent HTTP requests.

[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.then(() => {
        console.log(n);
        return new Promise(res => setTimeout(res, 1000));
    });
}, Promise.resolve()).then(
    () => console.log('done'),
    (e) => console.log(e)
);
// will log 1, 3, 5, 7, 9, 'done' in 1s intervals

Explanation:

  1. We call [.reduce()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce>) on a source array, and provide [Promise.resolve()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve>) as an initial value.
  2. Every element reduced will add a [.then()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then>) to the initial value.
  3. [reduce()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce>)’s product will be Promise.resolve().then(…).then(…).
  4. We manually append a [.then(successHandler, errorHandler)](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then>) after the reduce, to execute successHandler once all the previous steps have resolved. If any step was to fail, then errorHandler would execute.

Note: The “then” reduction is a sequential counterpart of Promise.all().

The “catch” reduction

This variant of the pattern builds a [.catch()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch>) chain and might be used for sequentially probing a set of web servers for some mirrored resource until a working server is found.

var working_resource = 5; // one of the values from the source array
[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.catch(() => {
        console.log(n);
        if(n === working_resource) { // 5 is working
            return new Promise((resolve, reject) => setTimeout(() => resolve(n), 1000));
        } else { // all other values are not working
            return new Promise((resolve, reject) => setTimeout(reject, 1000));
        }
    });
}, Promise.reject()).then(
    (n) => console.log('success at: ' + n),
    () => console.log('total failure')
);
// will log 1, 3, 5, 'success at 5' at 1s intervals

Explanation:

  1. We call [.reduce()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce>) on a source array, and provide [Promise.reject()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject>) as an initial value.
  2. Every element reduced will add a [.catch()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch>) to the initial value.
  3. [reduce()](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce>)’s product will be Promise.reject().catch(...).catch(...).