最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

asynchronous - Promise.all for objects in Javascript - Stack Overflow

programmeradmin1浏览0评论

Promise.all can turn [Promise a, Promise b] into Promise [a, b], which is super useful, but is there also a way to turn {a: Promise a, b: Promise b} into Promise {a, b}.

The use case is:

I have a function that loads some files from a website and gives back error messages in the case that it failed. This means, that its signature is information -> {values: values, messages: messages}.

But the whole check is async, so it turns out to be information -> {values: Promise values, messages: promise messages}

Promise.all can turn [Promise a, Promise b] into Promise [a, b], which is super useful, but is there also a way to turn {a: Promise a, b: Promise b} into Promise {a, b}.

The use case is:

I have a function that loads some files from a website and gives back error messages in the case that it failed. This means, that its signature is information -> {values: values, messages: messages}.

But the whole check is async, so it turns out to be information -> {values: Promise values, messages: promise messages}

Share Improve this question asked May 18, 2017 at 14:20 hgieselhgiesel 5,6582 gold badges33 silver badges59 bronze badges 5
  • 2 Promise.All([information.values, information.messages]).then(() => {//success}).catch((err) => {//error}), doesn't do the job ? – codtex Commented May 18, 2017 at 14:25
  • Why not change your function to have the signature information -> Promise {values: values, messages: messages} right away? Also why does it return both values and messages at the same time, shouldn't it return either? – Bergi Commented May 18, 2017 at 17:55
  • @Bergi it's more like it's logging, not really displaying one single error message – hgiesel Commented May 18, 2017 at 17:57
  • @hgiesel OK, I understand that, but is there any reason why the logging promise would resolve at a different time than the values promise? – Bergi Commented May 18, 2017 at 18:01
  • The async-q library's parallel() function does exactly this: npmjs./package/async-q#parallel – slebetman Commented Apr 1, 2024 at 20:35
Add a ment  | 

5 Answers 5

Reset to default 4

Here's my super simple solution:

export const objectZip = (keys, values) =>
  keys.reduce(
    (others, key, index) => ({
      ...others,
      [key]: values[index],
    }),
    {}
  );

export const objectPromise = async obj =>
  objectZip(Object.keys(obj), await Promise.all(Object.values(obj)));

You could do it manually:

function objectPromise(obj) {
    return Promise.all(Object.keys(obj).map(function (key) {
        return Promise.resolve(obj[key]).then(function (val) {
            return {key: key, val: val};
        });
    })).then(function (items) {
        var result = {};
        items.forEach(function (item) {
            result[item.key] = item.val;
        });
        return result;
    });
}

usage

var testObj = {
    a: Promise.resolve("a"),
    b: Promise.resolve("b"),
    c: "c"
};

objectPromise(testObj).then(function (obj) {
    console.log(obj);
});
//> { a: 'a', b: 'b', c: 'c' }

Same thing in ES6 syntax, if you prefer that:

var objectPromise = obj => Promise.all(
    Object
    .keys(obj)
    .map(key => Promise.resolve(obj[key]).then(val => ({key: key, val: val})))
).then(items => {
    let result = {};
    items.forEach(item => result[item.key] = item.val);
    return result;
});

No as i know but you can prepare a return object and you will know when its ready

function multipleAsyncJobs(){
    ret = {};
    var a = new Promise(function(resolve, reject){
        ret.a = someVal; // set 
        resolve();
    })
    var b = new Promise(function(resolve, reject){
        ret.b = someVal; // set 
        resolve();
    })
    return new Promise(function (resolve, reject) {
        Promise.all([a,b]).then(function(){
            resolve(ret)
        })
    })
}

u can use this func like this so that returns a promise as usual

multipleAsyncJobs().then(ret=>{
console.log(ret.a)
})

I would dare to suggest another option (with some further hints):

export async function promiseAllOfObject(obj) {
  const values = await Promise.all(Object.values(obj));
  return Object.keys(obj).reduce(
    (res, key, index) => (res[key] = values[index], res),
    {}
  );
}

Respectively replacing Promise.all to Promise.allSettled will give you promiseAllOfObjectSettled() function.

And, as a small bonus, here is typescript version (replacing to Promise.allSettled works the same as above):

export async function promiseAllOfObject<
  T extends Record<string, unknown> = Record<string, unknown>,
>(obj: {
  [P in keyof T]: Promise<T[P]>;
}): Promise<T> {
  const values = await Promise.all(Object.values(obj));
  return Object.keys(obj).reduce((res, key, index) => {
    res[key] = values[index];
    return res;
  }, {} as Record<string, unknown>) as T;
}

With Object.fromEntries(iterable), since ES10 / ES2019, similiar to this post but added types:

async function promiseAllOfObject<T extends Object>(obj: T): Promise<{
    [key in keyof T]: Awaited<T[key]>
}> {
    const entries = Object.entries(obj).map(async ([key, value]) => [key, await value])
    return Object.fromEntries(await Promise.all(entries))
}
发布评论

评论列表(0)

  1. 暂无评论