-1

Short questions: Why is there no Promise.chain in Javascript (comparable to Promise.all)? Is my implementation o.k.?

My 'codec' behaved wrong:

  1. Reading a graph from a XML file
  2. Creating all nodes (the creation method returns a promise)
  3. Waiting for all node creations to finish
  4. Create all edges between the nodes

The problem: The order of the database calls for the node creation (Step 2) got mixed up at execution time.

Solution: I had to chain the database calls in correct order before the methods became executed.

/**
 * chains a list of functions (that return promises) and executes them in the right order
 * [function() {return Promise.resolve();}, function() {return Promise.resolve();}]
 *
 * @param funcs is an array of functions returning promises
 * @returns {Promise}
 */
function chain_promises(funcs) {
    if (funcs.length < 1) {
        return Promise.resolve();
    }
    var i = 0;
    return chain_executor(funcs, i);
}

/**
 * Recursive help method for chain_promises
 * 1) executes a function that returns a promise (no params allowed)
 * 2) chains itself to the success resolve of the promise
 *
 * @param funcs is an array of functions returning promises
 * @param i is the current working index
 */
function chain_executor(funcs, i) {
    var promise = funcs[i]();
    return promise.then(function(){
        console.log(i);
        if (funcs.length > i+1) {
            return chain_executor(funcs, i+1);
        } else {
            return Promise.resolve();
        }
    })
}
Danipol
  • 79
  • 1
  • 5

1 Answers1

1

Using Array#reduce you can create this function

const chain_promises = arrayOfFn => arrayOfFn.reduce((promise, fn) => 
    promise.then(results => 
        fn().then(result => 
            results.concat(result)
        )
    ), Promise.resolve([])
);

or if you're into one-liners

const chain_promises = arrayOfFn => arrayOfFn.reduce((promise, fn) => promise.then(results => fn().then(result => results.concat(result))), Promise.resolve([]));

These have the added benefit that the resolved values are all available in the .then

e.g.

const chain_promises = arrayOfFn => arrayOfFn.reduce((promise, fn) => 
    promise.then(results => 
        fn().then(result => 
            results.concat(result)
        )
    ), Promise.resolve([])
);

const wait_promise = (time, result) => new Promise(resolve => setTimeout(resolve, time, result));
var funcs = [ 
    () => wait_promise(300, 'p1').then(value => ({value, date: new Date()})),
    () => wait_promise(400, 'p2').then(value => ({value, date: new Date()})),
    () => wait_promise(100, 'p3').then(value => ({value, date: new Date()}))
];
const start = new Date();
chain_promises(funcs)
.then(results => 
    results.reduce((a, b) => {
        console.log(b.value, b.date - a);
        return b.date;
    }, start)
);

Also, passing an empty array to this function won't break - you'll end up with an empty array as the resolved value

Jaromanda X
  • 53,868
  • 5
  • 73
  • 87