chevron-left chevron-right

Piotr Nalepa Frontend, architektura i AI

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

Ta wersja
blog.piotrnalepa.pl/en/2020/03/18/dealing-with-promise-all-and-a-bunch-of-async-functions
Opublikowano
Autor
, Staff Software Engineer
Kategoria
JavaScript
Uwagi
Napisz do mnie · Napisz na X

Ten wpis ma 6 lat. Od tego czasu przeglądarki i narzędzia mogły się zmienić, więc zanim użyjesz kodu, sprawdź go z aktualną dokumentacją.

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.

Sekcja 1The 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:

Przykład 1JavaScript
1
2
3
4
5
6
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:

Przykład 2JavaScript
1
2
3
4
[
    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!

Sekcja 2The second approach

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

Przykład 3JavaScript
1
2
3
4
5
6
7
8
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.

Sekcja 3The final approach

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

Przykład 4JavaScript
1
2
3
4
5
6
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.

Sekcja 4Summary

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.

Udostępnij
Uwagi

O autorze

Staff Software Engineer

Piszę na tym blogu od 2009 roku, a strony i aplikacje webowe tworzę zawodowo od 14 lat. Obecnie w Bishop Fox prowadzę frontend platformy Cosmos, od samego początku projektu. Wcześniej pracowałem m.in. w OLX, KUDO, Auto1 i eZ Systems. Piszę tu o tym, czego nauczyłem się w praktyce: o JavaScripcie, TypeScripcie, Reakcie, CSS-ie i architekturze frontendu. Występowałem też jako prelegent na konferencjach w Polsce i Europie. Masz pytanie albo pomysł na wpis? Daj znać!