Equivalent of BlueBird Promise.props for ES6 Promi

2019-06-23 02:26发布

问题:

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