Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Equivalent of BlueBird Promise.props for ES6 Promises?

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.

like image 708
pete Avatar asked Jun 17 '17 04:06

pete


5 Answers

An implementation of Bluebird.props that works on plain objects:

/**
 * This function maps `{a: somePromise}` to a promise that
 * resolves with `{a: resolvedValue}`.
 * @param {object} obj
 * @returns {Promise<object>}
 */
function 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;
    })
}
like image 121
golopot Avatar answered Nov 16 '22 02:11

golopot


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);
}
like image 34
slebetman Avatar answered Nov 16 '22 04:11

slebetman


Alternative implementation combining ES6+ Object.entries() and Object.fromEntries():

async function pprops(input) {
    return Object.fromEntries(
        await Promise.all(
            Object.entries(input)
                .map(
                    ([k, p])=>p.then(v=>[k, v])
                )
        )
    );
};
like image 35
bitifet Avatar answered Nov 16 '22 03:11

bitifet


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

like image 1
Jaromanda X Avatar answered Nov 16 '22 03:11

Jaromanda X


I have two different implementations using ES6 async functions:

async function PromiseAllProps(object) {
    const values = await Promise.all(Object.values(object));
    Object.keys(object).forEach((key, i) => object[key] = values[i]);
    return object;
}

One line shorter, but less optimized:

async function PromiseAllProps(object) {
    const values = await Promise.all(Object.values(object));
    return Object.fromEntries(Object.keys(object).map((prop, i) => ([prop, values[i]])));
}

Example

const info = await PromiseAllProps({
    name: fetch('/name'),
    phone: fetch('/phone'),
    text: fetch('/foo'),
});

console.log(info);
{
    name: "John Appleseed",
    phone: "5551234",
    text: "Hello World"
}
like image 1
Vitim.us Avatar answered Nov 16 '22 02:11

Vitim.us