问题
I would like to wait for a map of word to Promise to finish. BlueBird has Promise.props which accomplishes this, but is there a clean way to do this in regular javascript? I think I can make a new object which houses both the word and the Promise, get an array of Promises of those objects, and then call Promise.all and put them in the map, but it seems like overkill.
回答1:
If you are dealing with a Map with values that are promises (or a mix of promises and non-promises) - and you want the final resolved value to be a Map
with all values resolved
const mapPromise = map =>
Promise.all(Array.from(map.entries()).map(([key, value]) => Promise.resolve(value).then(value => ({key, value}))))
.then(results => {
const ret = new Map();
results.forEach(({key, value}) => ret.set(key, value));
return ret;
});
Although, I bet someone has a slicker way to do this, some of the new ES2015+ stuff is still new to me :p
回答2:
It would be advisable to use a library like bluebird for this. If you really want to do this yourself, the main idea is to:
- Resolve each of the map values and connect the promised value back with the corresponding key
- Pass those promises to
Promise.all
- Convert the final promised array back to a Map
I would make use of the second argument of Array.from
, and the fact that an array of key/value pairs can be passed to the Map
constructor:
Promise.allMap = function(map) {
return Promise.all( Array.from(map,
([key, promise]) => Promise.resolve(promise).then(value => [key, value])
) ).then( results => new Map(results));
}
// Example data
const map = new Map([
["Planet", Promise.resolve("Earth")],
["Star", Promise.resolve("Sun")],
["Galaxy", Promise.resolve("Milky Way")],
["Galaxy Group", Promise.resolve("Local Group")]
]);
// Resolve map values
Promise.allMap(map).then( result => console.log([...result]) );
.as-console-wrapper { max-height: 100% !important; top: 0; }
回答3:
The following is a simple implementation that works on plain objects, so that
makePromiseFromObject({a: Promise.resolve(1)})
is a Promise that resolves with {a: 1}
.
const makePromiseFromObject = (obj) => {
const keys = Object.keys(obj)
const values = Object.values(obj)
return Promise.all(values)
.then(resolved => {
const res = {}
for (let i = 0; i < keys.length; i += 1) res[keys[i]] = resolved[i]
return res
})
}
回答4:
if you use ramda you can do it like so:
export const promiseProps: <T>(obj: {[x: string]: Promise<T>}) => Promise<{[x: string]: T}> =
(obj) => Promise.all(R.values(obj)).then(R.zipObj(R.keys(obj)));
回答5:
You can simply write it using Promise.all + reduce
const promiseProps = (props) => Promise.all(Object.values(props)).then(
(values) => Object.keys(props).reduce((acc, prop, index) => {
acc[prop] = values[index];
return acc;
}, {})
);
回答6:
The venerable async.js library has a promisified counterpart: async-q
The promisified async-q
library supports all the functions in the async
library. Specifically async.parallel()
. At first glance async.parallel()
looks just like Promise.all()
in accepting an array of functions (note one difference, an array of functions, not promises) and run them in parallel. What makes async.parallel
special is that it also accepts an object:
const asyncq = require('async-q');
async function foo () {
const results = await asyncq.parallel({
something: asyncFunction,
somethingElse: () => anotherAsyncFunction('some argument')
});
console.log(results.something);
console.log(results.somethingElse);
}
来源:https://stackoverflow.com/questions/44600771/equivalent-of-bluebird-promise-props-for-es6-promises