loading...

Dealing with Promise.all() and a bunch of async functions

sunpietro profile image Piotr Nalepa Originally published at blog.piotrnalepa.pl ・3 min read

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 async/await approach and I was going to use Promise.all() function to resolve all of the async requests at the same time, when all of them are resolved.

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.

The first approach

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 Promise.all() function. Just like that:

Promise.all([
    await dispatch(fetchDataFromOneSource),
    await dispatch(fetchDataFromAnotherSource)
])
.then([data1, data2] => {})
.catch(error => console.log(error))

The code listing above is simplified in order to focus on the most important part.

As you can see, I'm using:

[
    await dispatch(fetchDataFromOneSource),
    await dispatch(fetchDataFromAnotherSource)
]

as an input param of Promise.all(). As we all know, async/await 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 then() part is run and everyone is happy.

In my case, there were specific situations when one of the async functions should fail and this should prevent from running a callback of then() part. I expected that catch() will be invoked instead.
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!

The second approach

At the time being I was rushed by the deadline and I've come up with a following solution:

Promise.all([
    await dispatch(fetchDataFromOneSource)
        .catch(handleError),
    await dispatch(fetchDataFromAnotherSource)
        .catch(handleError)
])
.then([data1, data2] => {})
.catch(handleError)

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.

The final approach

Finally, after thinking for hours. I realised where was the mistake and how to make the previous version more elegant:

await Promise.all([
    dispatch(fetchDataFromOneSource),
    dispatch(fetchDataFromAnotherSource)
])
.then([data1, data2] => {})
.catch(error => console.log(error))

This also worked as previously, but the final piece of code looks better and it's less hackish now.

It's worth to mention, that running await Promise.all() 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 then() callback param.

Summary

By writing this article I wanted to clarify the statement I wrote on Twitter:

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.

I hope this article clarified it and it will help you solving issues in your projects.

Posted on by:

sunpietro profile

Piotr Nalepa

@sunpietro

I'm a web developer with passion for my job. I love sharing my knowledge with fellow developers at my work and by writing articles about web development on personal blog

Discussion

markdown guide