skip to Main Content

I have an object with multiple properties and a few of them contain promises.
Now i want to wait until every promise is resolved and then the properties should contain the value of the promise

This is what i have so far, unfortunately the object o still contains the fullfilled promises on the properties o3, o4, o5:

var f_o_data = function(b_reject){

    return new Promise(
        function(
            f_resolve, 
            f_reject
        ){

            window.setTimeout(function(){

                var n_ts_ms = parseInt(new Date().getTime());
                // if(n_ts_ms % 2 == 0){
                //     f_reject(`i rejected because n_ts_ms ${n_ts_ms} % 2 == 0 is true :shrug:`)
                // }
                if(b_reject){
                    f_reject('i rejected because true was passed to function')
                }
                f_resolve(
                    {
                        n_ts_ms: n_ts_ms,
                        s: 'i am the result object', 
                        n: 23, 
                        b: true, 
                        a_n: [1,2,3], 
                        a_o:[{n:2, n:3}, {n:3}]
                    }
                )

            },parseInt(Math.random()*3333+555))
        }
    )
}
var f_o__filled_asyncally = async function(){

    var o = {
        b: true, 
        n: 2, 
        s: 'just a string', 
        o: {n:22}, 
        a_n: [1,2,3],
        a_o:[{n:2, n:3}, {n:3}],
        o1: await f_o_data(),// those two first async functions will be executed one after another because we use await keyword
        o2: await f_o_data(),// 
        o3: f_o_data(),// theese three can load parallel
        o4: f_o_data().then(function(o){return o}),// theese three can load parallel
        o5: f_o_data(),// theese three can load parallel
        // o6: f_o_data(true),// theese three can load parallel
    }
    return Promise.all(Object.values(o)).then(
        function(a_o_promise){
            return o
        }
    )
    // console.log(o)
    // console.log(o.o3)
    // console.log(o.o4)
    // console.log(o.o5)
    // return o;
}

var o_my_object_i_want_to_fill_asyncally = await f_o__filled_asyncally();
console.log(o_my_object_i_want_to_fill_asyncally)

2

Answers


  1. Chosen as BEST ANSWER

    i think i will go with this

    var f_o__filled_asyncally = async function(o){
    
        var a_s_prop_name = Object.keys(o);
        return Promise.all(Object.values(o)).then(
            function(a_value){
                var a_a_v = a_s_prop_name.map((s_prop_name, n_idx) => [s_prop_name, a_value[n_idx]]);
                return Object.fromEntries(a_a_v)
            }
        )
    }
    
    var o = {
        b: true, 
        n: 2, 
        s: 'just a string', 
        o: {n:22}, 
        a_n: [1,2,3],
        a_o:[{n:2, n:3}, {n:3}],
        o1: await f_o_data(),// those two first async functions will be executed one after another because we use await keyword
        o2: await f_o_data(),// 
        o3: f_o_data(),// theese three can load parallel
        o4: f_o_data().then(function(o){return o}),// theese three can load parallel
        o5: f_o_data(),// theese three can load parallel
        // o6: f_o_data(true),// theese three can load parallel
    }
    var o_my_object_i_want_to_fill_asyncally = await f_o__filled_asyncally(o);
    console.log(o_my_object_i_want_to_fill_asyncally)
    
    
    
    

  2. There are at least two answers to this question:

    1. An answer for f_o__filled_asyncally,specifically, making it return a promise for an object that will have all the values as non-promises.

    2. A general answer to the question in the title: Going from an object with some properties that are promises to an object with all non-promise values. But because of the sequential nature of one aspect of the code in the question, the general answer won’t quite apply to that sample code.

    The f_o__filled_asyncally-specific answer

    Wait to build your object until you have all of the information:

    const f_o__filled_asyncally = async function () {
        // Do the work first
        const [
            [o1, o2], 
            o3,
            o4,
            o5
        ] = await Promise.all([
            // All outer elements work in parallel
            (async () => [
                await f_o_data(), // These two are sequential
                await f_o_data(),
            ])(),
            f_o_data(),
            f_o_data().then(function (o) {
                // There's no point to this `then` call, but
                // I've left it in case you had something
                // in it that you didn't show
                return o;
            }),
            f_o_data(),
            // f_o_data(true), // Not sure why `o6` is commented out
        ]);
    
        // Build and return the object
        const result = {
            b: true,
            n: 2,
            s: "just a string",
            o: { n: 22 },
            a_n: [1, 2, 3],
            a_o: [{ n: 2, n: 3 }, { n: 3 }],
            o1,
            o2,
            o3,
            o4,
            o5,
            // o6,
        };
        return result;
    };
    

    You might want to split out the o1 and o2 part more explicitly:

    const f_o__filled_asyncally = async function () {
        // Do the work first
        const promiseForO1AndO2 = (async () => [
            await f_o_data(), // These two are sequential
            await f_o_data(),
        ])();
        const [
            [o1, o2], 
            o3,
            o4,
            o5
        ] = await Promise.all([
            // All outer elements work in parallel
            promiseForO1AndO2,
            f_o_data(),
            f_o_data().then(function (o) {
                // There's no point to this `then` call, but
                // I've left it in case you had something
                // in it that you didn't show
                return o;
            }),
            f_o_data(),
            // f_o_data(true), // Not sure why `o6` is commented out
        ]);
    
        // Build and return the object
        const result = {
            b: true,
            n: 2,
            s: "just a string",
            o: { n: 22 },
            a_n: [1, 2, 3],
            a_o: [{ n: 2, n: 3 }, { n: 3 }],
            o1,
            o2,
            o3,
            o4,
            o5,
            // o6,
        };
        return result;
    };
    

    The general answer

    This probably doesn’t quite fit your scenario because you have those two calls that have to be sequential, but it fits the title of the question:

    async function awaitAllProperties(obj) {
        const entries = await Promise.all(Object.entries(obj).map(
            async ([key, value]) => [key, await value]
        ));
        return Object.fromEntries(entries);
    }
    

    That will accept an object, wait for the promises (if any) on any of its properties to be settled, and return a new object with the fulfillment values.

    Again, because you have a pair of operations you’ve said you want done sequentially, it wouldn’t quite apply to the example code though.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search