5

I have an array of resolved Promises:

[Promise, Promise, Promise, ...]

Each of these promises when resolved returns a value. How do I create a function that returns the map of this array of promises to the value that each promise resolves to?

[value_1, value_2, value_3, ...]

Here's the closest I've gotten so far:

const mapPromisesToValues = promises => {
    Promise.all(promises, values => {
        // how do I return these values from mapPromisesToValues
        return values
    });
}

To be more specific, the reason why I ask is because I have a collection of arrays of Promises.

const collection_1 = [Promise, Promise, Promise, ...];
const collection_2 = [Promise, Promise, Promise, ...];
//...

and I want to batch these collection of promises mapped into a collection of values into 1 object, that I will then pass into another function that will be called once - in this case React's setState:

this.setState({
    ...this.state,
    values_1,
    values_2,
    //...
});
0

3 Answers 3

7

I have an array of resolved Promise ... how do I return these values from mapPromisesToValues

Even though you know the promises are resolved, you can't return a map of their values from your function. The only way to get the value of a promise is via a then callback, and that callback is guaranteed to be called asynchronously, which means that your function cannot return the value; it can only return a promise of the value (e.g., as Promise.all does).

You'll have to just have your function return the Promise.all and have the consumer of the function use it.


Re your edit:

To be more specific, the reason why I ask is because I have a collection of arrays of Promises.

const collection_1 = [Promise, Promise, Promise, ...];
const collection_2 = [Promise, Promise, Promise, ...];

//...

and I want to batch these collection of promises mapped into a collection of values into 1 object, that I will then pass into another function that will be called once - in this case React's setState:

this.setState({
    ...this.state,
    values_1,
    values_2,
    //...
});

That's fine, you don't need to do that synchronously. Simply:

Promise.all([
    Promise.all(collection_1),
    Promise.all(collection_2),
    // etc.
])
.then(([values_1, values_2, /*etc*/]) => {
    this.setState({values_1, values_2,/*etc*/});
});

Note that I left off ...this.state there. Two reasons:

  1. If you're setting state based on existing state, you must use the callback version of setState, not the one accepting an object; and

  2. State updates can be partial, so ...this.state is unnecessary extra work.


Depending on your coding environment, you may find it useful to adopt async/await (for instance, if you're transpiling, or you're doing this on Node.js can can use an up-to-date copy of Node.js). async/await lets you write your code according to its logical flow, rather than its synchronous flow. Within an async function, you use await to suspend the function and wait for a promise to resolve. async functions are syntactic sugar for functions that return promises, and await is syntactic sugar for consuming promises (e.g., then and catch).

To make the transition from synchronous-flow to logical-flow, you make your entry point an async function that you handle errors from:

(async () => {
    // Your logical flow code here
}).catch(error => {
    // Handle the error
});

Then, your function could be an async function:

async function example() {
    // ...
    return await Promise.all(thePromises)
}

...which any other async function can use via await:

let values = await example();
Sign up to request clarification or add additional context in comments.

3 Comments

I see that you've wrapped Promise.all() around each collection, creating a collection of Promise.all's. What does Promise.all() return? This is hurting my brain.
This works perfectly, thank you. Just a couple more questions so I can wrap my head around this - the then's function's argument is an array of values - is this some form of destructuring? Was not aware you can destructure arrays too
@jchi2241 - You have multiple arrays of promises, so the above uses Promise.all to wait for all of the promises in an array to complete. Since we're doing that with several arrays, we use another Promise.all to wait for all the promises from those Promise.alls to complete. The final result is an array of arrays. You're exactly right that when we consume that array of arrays, we're using destructuring to receive them as individual array parameters rather than a single array of arrays parameter.
1

You can't get the values from the promises synchronously by the nature of promises, sadly. You have to do this:

const mapPromisesToValues = promises => {
  return Promise.all(promises);
}

mapPromisesToValues(promises).then(values => console.log(values));

Comments

0
const values = await Promise.all(promiseArr);

2 Comments

var a = new Promise(function(res, rej){res(5);}); var b = new Promise(function(res, rej){res(6);}); var d = await Promise.all([a,b]); console.log(d);
For me it's the only right answer... I can't find any reason to add anything. +1 from me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.