Fliggerty
Fliggerty

Reputation: 83

How to use Promise.all() inside of another promise .then chain

I'm pretty sure I am over-complicating this, so some help is greatly appreciated!

I have a class that contains several slow methods. So I am using promises in order to use the methods sequentially without using callbacks.

One of the methods returns an array of data; it is necessary to loop through this array and execute a different method on each value. In order to do this, I am using Promise.all(). The problem is that this loop does not complete before the original promise chain moves onto the next .then() in the list.

Class:

class worker {
    slowFunctionOne(list) {
        return new Promise(function(resolve, reject) {
            for ( var i in list ) {
                list[i] = ( list[i] * 2 );
            }
            setTimeout(() => resolve(list), 1000);
        });
    }
    slowFunctionTwo(number) {
        return new Promise(function(resolve, reject) {
            number = ( number / 2 );
            setTimeout(() => resolve(number), 1000);
        });
    }
}
module.exports = worker;

Main:

const worker = require('./worker');

var w = new worker();

var list = [2,4,6,8,10];

var promises = [];

w.slowFunctionOne(list)
    .then(function(value) {
        console.log("After first method:",value);
        for ( i in value ) {
            promises.push(w.slowFunctionTwo(value[i]));
        }
        var output = [];
        Promise.all(promises)
            .then(function(number) {
                console.log("After second method:",number);
                output = number;
            });
        return output;
    })
    .then(function(val) {
        console.log("Finally:",val);
    });

Output:

After first method: [ 4, 8, 12, 16, 20 ]
Finally: []
After second method: [ 2, 4, 6, 8, 10 ]

So you can see that slowFunctionOne() runs and returns an array. It then iterates through that array and executes slowFunctionTwo() on each value. My intention is for all of the modified values from slowFunctionTwo() will be put into the "output" variable after the Promise.all() is complete; finally it should go to the last .then() in the original chain and echo out "output."

As you can see, the code inside the last .then() is executing before Promise.all() is complete.

So how do I make the final .then() wait until everything inside the nested promise chain is complete? I suspect that async/await is the right answer, but I can't figure out how to utilize that for the nested portion without screwing up the top level chain.

Upvotes: 1

Views: 1810

Answers (1)

apsillers
apsillers

Reputation: 115920

Your code does not wait for Promise.all before your top-level Promise chain continues on via return output.

The solution here is: don't use output at all. You need to return Promise.all(...).then(...) (instead of return output) so that your final top-level then waits for the Promise.all's then to finish first.

return Promise.all(promises)
        .then(function(number) {
            console.log("After second method:",number);
            return number;
        });

By doing return number inside the return Promise.all(...).then(...), you ensure that number is passed in as the val argument to the top-level then handler.

Upvotes: 1

Related Questions