avatarPaul Vaneveld

Summary

This context discusses three methods of handling an iterable of promises in JavaScript: Promise.all(), Promise.allSettled(), and for await...of.

Abstract

The context provides an in-depth comparison of three methods for handling iterables of promises in JavaScript: Promise.all(), Promise.allSettled(), and for await...of. It explains the functionality and use cases of each method, along with examples and performance considerations. The article concludes by recommending the appropriate method based on the specific requirements of the task at hand.

Bullet points

  • The context discusses handling iterables of promises in JavaScript.
  • It introduces three methods: Promise.all(), Promise.allSettled(), and for await...of.
  • for await...of is comparable to its synchronous counterpart for of, but handles asynchronous codes within the loop.
  • Promise.all() takes an iterable of promises as input and returns an array containing the result of all promises when all are fulfilled.
  • The main difference between for await...of and Promise.all() is that the former handles promises one by one, while the latter handles them concurrently.
  • Promise.all() is faster than for await...of, but the latter provides more granular control over promises.
  • Promise.allSettled() is similar to Promise.all(), but returns a promise that resolves after all given promises have either fulfilled or rejected.
  • The article recommends using Promise.all() if the order of resolved promises is not important and all calls need to succeed, and Promise.allSettled() if the order is not important and individual calls do not need to be successful.
  • The article provides examples and performance considerations for each method.
  • The article concludes by summarizing the recommended use cases for each method.

Promise.all() vs. Promise.allSettled() vs. for await…of

On how to handle asynchronous iterables

Photo by Radowan Nakif Rehan on Unsplash

Writing modern JavaScript most of the time involves handling promises. More often than not, it involves handling lots of them. The options for processing promises are manifold. There are a lot of guns in the weaponry. And although you may hit a target point blank with a sniper, getting the weapon of choice right makes the job a whole lot easier.

To help you take aim properly, I will discuss three methods of handling an iterable of promises: Promise.all() , Promise.allSettled() and for await...of .

For await…of

The asynchronous For await...of is very much comparable to its synchronous brother for of : you can loop over an iterable like an Array , Map or Set . For await of distinguishes itself by the possibility to handle asynchronous codes within the loop.

So let’s assume we have an array with the ids of 5 Pokemon. Using for await…of, we can loop over the id’s one by one, and fetch the name of the associated Pokemon using the PokéApi. If an error occurs in one of the calls, we can catch and handle it, to continue with the remainder of the loop afterwards.

Promise.all()

So how would we go about fetching the Pokemon names using Promise.all() ? This function takes an iterable of promises as its input parameter. So we can .map over the ids, fetch the names, and supply the asynchronous map as input to Promise.all . When all promises are fulfilled, the function returns an array containing the result of all promises.

The main difference between “for await…of” and “Promise.all()”

So, except for the slight difference in the return value, what is the big difference between for await...of and Promise.all() . The most important difference is that Promise.all() handles its input promises concurrently, while for await...of resolves them one at the time. So, for example, using for await...of, we would be able the stop calling the pokeApi once we found Charmander, while Promise.all() would create all promises at the same time and only complete when all are resolved.

Using for await...of, you have more granular control of the promises. So if the order in which promises complete is important to you, for await...of is your preferred choice. However, the increased control isn’t free. The fact that for await...of handles promises one by one, makes it a lot slower. In fact, in case of our Pokemon fetching, almost twice as slow, as shown in the image below. So as a rule of thumb, I recommend using Promise.all() and only switch to for await...of if the concurrent handling of promises causes problems.

“Promise.all()” versus “Promise.allSettled()”

All the calls we made to the PokéApi so far were successful. But what if an error occurs fetching one of the Pokemons? Using for await of we catch the error within each iteration. So if, for example, fetching a Pokemon with id 2 failed, we can handle the error and jump into the next iteration.

In contrast, Promise.all() fails fast by default, meaning the whole promise is rejected in case a call fails. So if an error occurs while fetching the third Pokemon, execution stops and we receive an error message.

In some cases fail fast is very convenient. Assume for example, all Pokemon names are needed to perform a subsequent operation. In such a case failing fast is fine, since you do not want to waste resources on the remaining calls.

However, in other cases you want all calls to either reject or be fulfilled. For example, if the fetched Pokemons are used for a separate subsequent task, or we want to show and access error information about each call, failing fast is bothersome.

In these situations Promise.allSettled() is a more sensible choice. This function is very similar to Promise.all() , but instead of failing fast, it returns a promise that resolves after all of the given promises have either fulfilled or rejected. The result of the previous example, with an erroneous call at index === 2 , will look as follows using Promise.allSettled() . We see that four calls are fulfilled but the call with index 2 got rejected.

Conclusion

To sum up, the three methods are all capable of handling iterables of promises, but differ slightly in their functioning. Use for await of if the order in which promises are resolved is important to you. Use Promise.all() if the order isn’t important and you need all calls to succeed. Use Promise.allSettled() if the order isn’t important and you don’t absolutely need all individual calls to be successful.

Resources

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter and LinkedIn. Join our community Discord.

Programming
Software Development
JavaScript
Web Development
Computer Science
Recommended from ReadMedium