3

I'm experimenting with Promise.all, but the functions run when I push them into an array in the first place, so what is the point of promise.all at all? Here is an example:

async function foo(args) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(args)
            resolve(args)
        }, 500)
    });
}

function init() {
    var params = [10, 20, 30];
    var promises = [];

    for (let x of params) {
        promises.push(foo(x));
    }

    //do something with Promise.all(promises) here

    return;
}


init();

Output:

10
20
30

What am I doing wrong? I'm sure it's something silly and I'm probably going blind.

EDIT: Sorry I should clarify, I know how to actually call Promise.all, but I was under the impression that the promises would not be run until after you do the call.

I guess what I'm asking is if there is a way to "que" the functions so they don't run right away until I run Promise.all()?

Edit 2:

I see this was marked as duplicate / people saying it's not about promise.all, I WAS hoping to que the functions up to be used with promise.all at the end if at all possible instead of doing things manually as suggested by the linked post.

If that is not a possibility, please let me know.

Mankind1023
  • 7,198
  • 16
  • 56
  • 86
  • What output are you expecting? are you expecting `[10, 20, 30]` in the promise? – scagood Feb 14 '18 at 16:26
  • Now, you've completely changed your question to something different. Did you downvote my answer for answering what you originally asked? – jfriend00 Feb 14 '18 at 16:46
  • I didn't down vote anything. – Mankind1023 Feb 14 '18 at 17:46
  • "The impression that promises would not be run until after you call [promise.all]" is suspect. a) promises don't run, they are interface objects. b) the executor function supplied to the Promise constructor is called synchronously and returns before the constructor can return the new Promise object created. The logged output is entirely as expected because you've logged the result in the timer callbacks, which execute in the same order as placed in the timer queue. Specifying what the task requirements are before undertaking promise composition may help. – traktor Feb 15 '18 at 00:58

1 Answers1

6

Okay, first let us look at your foo function.

Here you have a Promise that has resolved to a Promise. What the async function declaration does is effectively making the function return a promise.

This means you can then use await inside the async function without worrying about the function resolution. For example:

// Lets say you have a 'long running' function that returns a promise.
const timeout = ms =>  new Promise(
    resolve => setTimeout(resolve, ms)
);

// What you can do is something like so:
async function foo(args) {
    await timeout(500);

    console.log(args);
    return args;
}

The 'timeout' function came from @Bergi. This does almost exactly the same thing as your first foo function.

// Lets say you 'foo' here.
const fooPromise = foo('Your args');

// The output here would be a pending Promise
// in chrome console: Promise {<pending>}

What your foo code does, is effectively the same, except it in practice does something like this:

function foo(args) {
    return new Promise(resolve1 => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log(args)
                resolve(args)
            }, 500)
        });
    });
}

This is rather redundant, but does not adversely affect how the program runs.


Secondly, let us look at the init function.

In JavaScript you don't need to use an 'Init', 'Main' or any equivalent. You can just start running your code, so your init code could be removed from the function and executed like so:

var params = [10, 20, 30];
var promises = [];

for (let x of params) {
    promises.push(foo(x));
}

//do something with Promise.all(promises) here

Now to making the Promises, again, there is nothing really 'wrong' with your code. In order to use 'Promise.all' here you simply pass the promises array to Promise.all as you commented. Promise.all returns a Promise that will contain an array of your generated promises. You can then access that the same way you'd access any other Promise.

// Use your promises
Promise.all(promises)

// Do what you need to do with the Promises
.then(output => {
    // Output = [10, 20, 30]
});

Your code using the 'for loop' can be replaced using an Array.prototype.map to quickly produce an array of promises, like so:

var params = [10, 20, 30];

Promise.all(params.map(foo))
.then(output => {
    // Output = [10, 20, 30]
});

Putting this together you would use the promises like so:

// A 'long running' function that returns a promise.
const timeout = ms =>  new Promise(
    resolve => setTimeout(resolve, ms)
);

// What you can do is something like so:
async function foo(args) {
    // A 'long running' function that returns a promise.
    await timeout(500);

    // Here you can manipulate the args like normal
    // e.g.:
    args = args ** 2;

    console.log(args);
    return args;
}

var params = [10, 20, 30];

Promise.all(params.map(foo))
.then(output => {
    // output = [100, 400, 900]
    console.log(output);
});

The output of this would be:

100
400
900
[100, 400, 900]

In your console.

scagood
  • 784
  • 4
  • 11