How much is the performance overhead for awaiting an already fulfilled Promise?












6















While doing code reviews, I've recently come across such kind of code blocks:



const promises = ;
const data = ;
for (let piece of pieces) {
for (let chunk of piece) {
promises.push(execute(chunk)); //execute returns a promise which is not yet fulfilled
}
data = await Promise.all(promises);
}


Here pieces is an array of arrays. Note that due to certain constraints we cannot await all Promises at once, hence this sort of chunking.



In my feedback, I write that this appears to be an anti-pattern as we are also awaiting Promises which were resolved in the previous iterations and the following is the proper way of handling such scenarios:



const data = ;
for (let piece of pieces) {
const promises = ;
for (let chunk of piece) {
promies.push(execute(chunk)); //execute returns a promise which is not yet fulfilled
}
data.push(... await Promise.all(promises));
}


At the end, data will be the same in both cases.



I understand how data is being populated in both cases. I would like to know how much is the performance overhead of awaiting an already fulfilled promise (which is happening in the first code block) and is it significant?










share|improve this question




















  • 1





    the two code blocks are not identical at all ... the first one will end up with less data than the second in data

    – Jaromanda X
    Nov 24 '18 at 6:52











  • The intent here is pretty unclear. Certainly if this is about gathering to data then both listings are likely not that ideal. To clarify comments I've seen here so far example 1 is "re-assigning" the data and 2. Is "attempting" to accumulate. Unfortunately it's all a bit "meta" to really understand context here. And without context, any answer really lacks any meaning. Best if the comments cool down and allow the OP to clarify.

    – Neil Lunn
    Nov 24 '18 at 6:55













  • if you take 2nd variant and await data outside the loops it would be fastest option

    – skyboyer
    Nov 24 '18 at 6:57






  • 1





    Sorry @sbmthakur I was distracted by the last part of the code and missed the nesting difference.

    – Mark Meyer
    Nov 24 '18 at 7:01






  • 1





    @CertainPerformance no, they are still Promises.

    – skyboyer
    Nov 24 '18 at 7:04
















6















While doing code reviews, I've recently come across such kind of code blocks:



const promises = ;
const data = ;
for (let piece of pieces) {
for (let chunk of piece) {
promises.push(execute(chunk)); //execute returns a promise which is not yet fulfilled
}
data = await Promise.all(promises);
}


Here pieces is an array of arrays. Note that due to certain constraints we cannot await all Promises at once, hence this sort of chunking.



In my feedback, I write that this appears to be an anti-pattern as we are also awaiting Promises which were resolved in the previous iterations and the following is the proper way of handling such scenarios:



const data = ;
for (let piece of pieces) {
const promises = ;
for (let chunk of piece) {
promies.push(execute(chunk)); //execute returns a promise which is not yet fulfilled
}
data.push(... await Promise.all(promises));
}


At the end, data will be the same in both cases.



I understand how data is being populated in both cases. I would like to know how much is the performance overhead of awaiting an already fulfilled promise (which is happening in the first code block) and is it significant?










share|improve this question




















  • 1





    the two code blocks are not identical at all ... the first one will end up with less data than the second in data

    – Jaromanda X
    Nov 24 '18 at 6:52











  • The intent here is pretty unclear. Certainly if this is about gathering to data then both listings are likely not that ideal. To clarify comments I've seen here so far example 1 is "re-assigning" the data and 2. Is "attempting" to accumulate. Unfortunately it's all a bit "meta" to really understand context here. And without context, any answer really lacks any meaning. Best if the comments cool down and allow the OP to clarify.

    – Neil Lunn
    Nov 24 '18 at 6:55













  • if you take 2nd variant and await data outside the loops it would be fastest option

    – skyboyer
    Nov 24 '18 at 6:57






  • 1





    Sorry @sbmthakur I was distracted by the last part of the code and missed the nesting difference.

    – Mark Meyer
    Nov 24 '18 at 7:01






  • 1





    @CertainPerformance no, they are still Promises.

    – skyboyer
    Nov 24 '18 at 7:04














6












6








6


1






While doing code reviews, I've recently come across such kind of code blocks:



const promises = ;
const data = ;
for (let piece of pieces) {
for (let chunk of piece) {
promises.push(execute(chunk)); //execute returns a promise which is not yet fulfilled
}
data = await Promise.all(promises);
}


Here pieces is an array of arrays. Note that due to certain constraints we cannot await all Promises at once, hence this sort of chunking.



In my feedback, I write that this appears to be an anti-pattern as we are also awaiting Promises which were resolved in the previous iterations and the following is the proper way of handling such scenarios:



const data = ;
for (let piece of pieces) {
const promises = ;
for (let chunk of piece) {
promies.push(execute(chunk)); //execute returns a promise which is not yet fulfilled
}
data.push(... await Promise.all(promises));
}


At the end, data will be the same in both cases.



I understand how data is being populated in both cases. I would like to know how much is the performance overhead of awaiting an already fulfilled promise (which is happening in the first code block) and is it significant?










share|improve this question
















While doing code reviews, I've recently come across such kind of code blocks:



const promises = ;
const data = ;
for (let piece of pieces) {
for (let chunk of piece) {
promises.push(execute(chunk)); //execute returns a promise which is not yet fulfilled
}
data = await Promise.all(promises);
}


Here pieces is an array of arrays. Note that due to certain constraints we cannot await all Promises at once, hence this sort of chunking.



In my feedback, I write that this appears to be an anti-pattern as we are also awaiting Promises which were resolved in the previous iterations and the following is the proper way of handling such scenarios:



const data = ;
for (let piece of pieces) {
const promises = ;
for (let chunk of piece) {
promies.push(execute(chunk)); //execute returns a promise which is not yet fulfilled
}
data.push(... await Promise.all(promises));
}


At the end, data will be the same in both cases.



I understand how data is being populated in both cases. I would like to know how much is the performance overhead of awaiting an already fulfilled promise (which is happening in the first code block) and is it significant?







javascript node.js asynchronous promise async-await






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 24 '18 at 12:39









Bergi

373k58561890




373k58561890










asked Nov 24 '18 at 6:43









sbmthakursbmthakur

456




456








  • 1





    the two code blocks are not identical at all ... the first one will end up with less data than the second in data

    – Jaromanda X
    Nov 24 '18 at 6:52











  • The intent here is pretty unclear. Certainly if this is about gathering to data then both listings are likely not that ideal. To clarify comments I've seen here so far example 1 is "re-assigning" the data and 2. Is "attempting" to accumulate. Unfortunately it's all a bit "meta" to really understand context here. And without context, any answer really lacks any meaning. Best if the comments cool down and allow the OP to clarify.

    – Neil Lunn
    Nov 24 '18 at 6:55













  • if you take 2nd variant and await data outside the loops it would be fastest option

    – skyboyer
    Nov 24 '18 at 6:57






  • 1





    Sorry @sbmthakur I was distracted by the last part of the code and missed the nesting difference.

    – Mark Meyer
    Nov 24 '18 at 7:01






  • 1





    @CertainPerformance no, they are still Promises.

    – skyboyer
    Nov 24 '18 at 7:04














  • 1





    the two code blocks are not identical at all ... the first one will end up with less data than the second in data

    – Jaromanda X
    Nov 24 '18 at 6:52











  • The intent here is pretty unclear. Certainly if this is about gathering to data then both listings are likely not that ideal. To clarify comments I've seen here so far example 1 is "re-assigning" the data and 2. Is "attempting" to accumulate. Unfortunately it's all a bit "meta" to really understand context here. And without context, any answer really lacks any meaning. Best if the comments cool down and allow the OP to clarify.

    – Neil Lunn
    Nov 24 '18 at 6:55













  • if you take 2nd variant and await data outside the loops it would be fastest option

    – skyboyer
    Nov 24 '18 at 6:57






  • 1





    Sorry @sbmthakur I was distracted by the last part of the code and missed the nesting difference.

    – Mark Meyer
    Nov 24 '18 at 7:01






  • 1





    @CertainPerformance no, they are still Promises.

    – skyboyer
    Nov 24 '18 at 7:04








1




1





the two code blocks are not identical at all ... the first one will end up with less data than the second in data

– Jaromanda X
Nov 24 '18 at 6:52





the two code blocks are not identical at all ... the first one will end up with less data than the second in data

– Jaromanda X
Nov 24 '18 at 6:52













The intent here is pretty unclear. Certainly if this is about gathering to data then both listings are likely not that ideal. To clarify comments I've seen here so far example 1 is "re-assigning" the data and 2. Is "attempting" to accumulate. Unfortunately it's all a bit "meta" to really understand context here. And without context, any answer really lacks any meaning. Best if the comments cool down and allow the OP to clarify.

– Neil Lunn
Nov 24 '18 at 6:55







The intent here is pretty unclear. Certainly if this is about gathering to data then both listings are likely not that ideal. To clarify comments I've seen here so far example 1 is "re-assigning" the data and 2. Is "attempting" to accumulate. Unfortunately it's all a bit "meta" to really understand context here. And without context, any answer really lacks any meaning. Best if the comments cool down and allow the OP to clarify.

– Neil Lunn
Nov 24 '18 at 6:55















if you take 2nd variant and await data outside the loops it would be fastest option

– skyboyer
Nov 24 '18 at 6:57





if you take 2nd variant and await data outside the loops it would be fastest option

– skyboyer
Nov 24 '18 at 6:57




1




1





Sorry @sbmthakur I was distracted by the last part of the code and missed the nesting difference.

– Mark Meyer
Nov 24 '18 at 7:01





Sorry @sbmthakur I was distracted by the last part of the code and missed the nesting difference.

– Mark Meyer
Nov 24 '18 at 7:01




1




1





@CertainPerformance no, they are still Promises.

– skyboyer
Nov 24 '18 at 7:04





@CertainPerformance no, they are still Promises.

– skyboyer
Nov 24 '18 at 7:04












1 Answer
1






active

oldest

votes


















1














The overhead is minuscule - it needs to iterate the already fulfilled promise, inspect it, take out the data and put it inside the result array. Assuming native promises, I expect this to be optimised and not need a roundtrip to the event loop, if you had thenables in the array then all of them would need to get resolved to a promise and that promise would need to be awaited asynchronously, taking a toll on the promise job queue.



The overhead in processing time will not be significant compared to the actual asynchronous work done in your execute function.



However, no matter how small the overhead is, the issue with the first version of your code is that its runtime complexity is quadratic: Promise.all needs to iterate the whole promises array every time. The more chunks * pieces you have, the more pronounced the effect will be. I agree with your review feedback and would recommend the second version of the code.






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53455835%2fhow-much-is-the-performance-overhead-for-awaiting-an-already-fulfilled-promise%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    The overhead is minuscule - it needs to iterate the already fulfilled promise, inspect it, take out the data and put it inside the result array. Assuming native promises, I expect this to be optimised and not need a roundtrip to the event loop, if you had thenables in the array then all of them would need to get resolved to a promise and that promise would need to be awaited asynchronously, taking a toll on the promise job queue.



    The overhead in processing time will not be significant compared to the actual asynchronous work done in your execute function.



    However, no matter how small the overhead is, the issue with the first version of your code is that its runtime complexity is quadratic: Promise.all needs to iterate the whole promises array every time. The more chunks * pieces you have, the more pronounced the effect will be. I agree with your review feedback and would recommend the second version of the code.






    share|improve this answer




























      1














      The overhead is minuscule - it needs to iterate the already fulfilled promise, inspect it, take out the data and put it inside the result array. Assuming native promises, I expect this to be optimised and not need a roundtrip to the event loop, if you had thenables in the array then all of them would need to get resolved to a promise and that promise would need to be awaited asynchronously, taking a toll on the promise job queue.



      The overhead in processing time will not be significant compared to the actual asynchronous work done in your execute function.



      However, no matter how small the overhead is, the issue with the first version of your code is that its runtime complexity is quadratic: Promise.all needs to iterate the whole promises array every time. The more chunks * pieces you have, the more pronounced the effect will be. I agree with your review feedback and would recommend the second version of the code.






      share|improve this answer


























        1












        1








        1







        The overhead is minuscule - it needs to iterate the already fulfilled promise, inspect it, take out the data and put it inside the result array. Assuming native promises, I expect this to be optimised and not need a roundtrip to the event loop, if you had thenables in the array then all of them would need to get resolved to a promise and that promise would need to be awaited asynchronously, taking a toll on the promise job queue.



        The overhead in processing time will not be significant compared to the actual asynchronous work done in your execute function.



        However, no matter how small the overhead is, the issue with the first version of your code is that its runtime complexity is quadratic: Promise.all needs to iterate the whole promises array every time. The more chunks * pieces you have, the more pronounced the effect will be. I agree with your review feedback and would recommend the second version of the code.






        share|improve this answer













        The overhead is minuscule - it needs to iterate the already fulfilled promise, inspect it, take out the data and put it inside the result array. Assuming native promises, I expect this to be optimised and not need a roundtrip to the event loop, if you had thenables in the array then all of them would need to get resolved to a promise and that promise would need to be awaited asynchronously, taking a toll on the promise job queue.



        The overhead in processing time will not be significant compared to the actual asynchronous work done in your execute function.



        However, no matter how small the overhead is, the issue with the first version of your code is that its runtime complexity is quadratic: Promise.all needs to iterate the whole promises array every time. The more chunks * pieces you have, the more pronounced the effect will be. I agree with your review feedback and would recommend the second version of the code.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 24 '18 at 12:37









        BergiBergi

        373k58561890




        373k58561890
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53455835%2fhow-much-is-the-performance-overhead-for-awaiting-an-already-fulfilled-promise%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Wiesbaden

            Marschland

            Dieringhausen