Dealing with Promise.all() and a bunch of async functions
Tags: javascript, async, promise
Published: 2020-07-02 05:55:08

<p>Recently I've been in the situation where I needed to resolve multiple async functions in paralel. The tricky part was that these functions were written using <strong>async/await</strong> approach and I was going to use <code>Promise.all()</code> function to resolve all of the async requests at the same time, when all of them are resolved.</p><!--more-->

<p>I'm not going to tell you much about Promises and async/await. I assume you have already gained proper knowledge regarding how to use them in your project.</p>
<h3>The first approach</h3>
<p>In order to handle such situation where I had a bunch of async functions I managed to put them all into an array and use it as a param of <code>Promise.all()</code> function. Just like that:</p>
<pre lang="javascript" line="1">Promise.all([
    await dispatch(fetchDataFromOneSource),
    await dispatch(fetchDataFromAnotherSource)
])
.then([data1, data2] => {})
.catch(error => console.log(error))
</pre>
<p>The code listing above is simplified in order to focus on the most important part.</p>
<p>As you can see, I'm using:</p>
<pre lang="javascript" line="1">[
    await dispatch(fetchDataFromOneSource),
    await dispatch(fetchDataFromAnotherSource)
]
</pre>
<p>as an input param of <code>Promise.all()</code>. As we all know, <code>async/await</code> approach is just a syntax sugar for Promises, so I expected to have all promises resolved when data is ready. It works perfectly fine, when all promises are resolved correctly. The <code>then()</code> part is run and everyone is happy.</p>
<p>In my case, there were specific situations when one of the async functions should fail and this should prevent from running a callback of <code>then()</code> part. I expected that <code>catch()</code> will be invoked instead.<br/>
I was so wrong! All of it failed silently and except showing errors in the browser console nothing happened in the UI, while it should!</p>
<h3>The second approach</h3>
<p>At the time being I was rushed by the deadline and I've come up with a following solution:</p>
<pre lang="javascript" line="1">Promise.all([
    await dispatch(fetchDataFromOneSource)
        .catch(handleError),
    await dispatch(fetchDataFromAnotherSource)
        .catch(handleError)
])
.then([data1, data2] => {})
.catch(handleError)
</pre>
<p>It solved my problem but it was not the most elegant solution in the world. It bothered me a lot. Duplicated error handlers for each promise was not the most optimal solution in my case.</p>
<h3>The final approach</h3>
<p>Finally, after thinking for hours. I realised where was the mistake and how to make the previous version more elegant:</p>
<pre lang="javascript" line="1">await Promise.all([
    dispatch(fetchDataFromOneSource),
    dispatch(fetchDataFromAnotherSource)
])
.then([data1, data2] => {})
.catch(error => console.log(error))
</pre>
<p>This also worked as previously, but the final piece of code looks better and it's less hackish now.</p>
<p>It's worth to mention, that running <code>await Promise.all()</code> allows you to assign its output to a variable and maybe destructure it, if needed, and then proceed with next actions instead of running the <code>then()</code> callback param.</p>
<h3>Summary</h3>
<p>By writing this article I wanted to clarify the statement I wrote on Twitter:</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">TIL: If any promise in Promise.all() will fail then catch assigned to Promise.all won’t work. You have to add catch to all promises in the array of promises used a Promise.all param. <a href="https://twitter.com/hashtag/javascript?src=hash&amp;ref_src=twsrc%5Etfw">#javascript</a></p>&mdash; Piotr Nalepa (@sunpietro) <a href="https://twitter.com/sunpietro/status/1239891678565187584?ref_src=twsrc%5Etfw">March 17, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 
<p><strong>I was wrong then. The catch will be invoked when the array of Promises contain the Promise objects itself, not the invokations of async functions.</strong></p>
<p>I hope this article clarified it and it will help you solving issues in your projects.</p>