Object literal (hash) with Promise.all

Viewed 3811

I have a situation where it would be quite convenient to use Promise.all like so Promise.all({}) instead of the more standard Promise.all([]).

but this doesn't seem to work

Promise.all({a:1,b:2}).then(function(val){
   console.log('val:',val);
});

whilst this does of course

Promise.all([1,2,3]).then(function(val){
   console.log('val:',val);
});

(what I would expect would be for Promise.all to map the values of the Object literal, but leave the keys intact.)

But the MDN docs for Promise seem to indicate that Promise all will work for any iterable. To my knowledge, an object literal {} is an iterable. So what am I missing?

8 Answers

Here is another async / await ES6 solution:

async function allOf(hash = {}) {
  const promises = Object.keys(hash).map(async key => ({[key]: await hash[key]}));
  const resolved = await Promise.all(promises);
  return resolved.reduce((hash, part) => ({...hash, ...part}), {});
}

This converts the keys into a promise that produces a single element hash. Then at the end we combine all the hashes in the array to a single hash. You could compact this to a one-liner even, at the cost of readability.

async function allOfOneLiner(hash = {}) {
  return (await Promise.all(Object.keys(hash).map(async k => ({[k]: await hash[k]})))).reduce((h, p) => ({...h, ...p}), {});
}

ES6 way

Promise.hashProperties = async function(object) {
    const keys = [];
    const values = [];

    for (const key in object) {
        keys.push(key);
        values.push(object[key]);
    }

    const results = await Promise.all(values);

    for (var i=0; i<results.length; i++)
        object[keys[i]] = results[i];

    return object;
};
Related