Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map an array of resolved promises to an array of values

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,
    //...
});
like image 464
jchi2241 Avatar asked Mar 07 '23 02:03

jchi2241


2 Answers

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();
like image 158
T.J. Crowder Avatar answered Mar 08 '23 17:03

T.J. Crowder


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));
like image 30
Tholle Avatar answered Mar 08 '23 17:03

Tholle