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)));