Introducing PromiViz - visualize and learn JavaScript promise APIs
Tags: javascript, codenewbie, beginners, node
Published: 2021-08-22 06:40:38

*If you found this article helpful, you will most likely find my tweets useful too. So here is the [Twitter Link](https://twitter.com/tapasadhikary) to follow me for information about web development and content creation. This article was originally published on my [Blog](https://blog.greenroots.info/).*

<hr />
Why does JavaScript `promise` sounds a bit more complex than many other topics? Besides the factors that we have [already discussed](https://blog.greenroots.info/series/javascript-promises), we also need to know how it executes, what's the background story? After spending a considerable amount of time practicing and thinking about the promises using pen and paper, I got an idea to make a simple yet powerful tool for developers.

# Meet PromiViz
![PromiViz](https://cdn.hashnode.com/res/hashnode/image/upload/v1629445649182/QtHHPixFe.png?border=1,CCCCCC&auto=compress)

[Promiviz](https://promiviz.vercel.app/) is an open-source tool to try out the promise methods in intuitive ways. You can configure promises with delays, rejections and run them to see what's exactly happening behind the scene. It captures the log of each of the operations so that your understanding gets firmed as you use it. It is a tool for developers by a developer! 

Please check out this short video to know more about the tool.

{% youtube webs_tRKIIg %}

Here are the important links:
- The app: [https://promiviz.vercel.app/](https://promiviz.vercel.app/)
- GitHub Repo: [https://github.com/atapas/promiviz](https://github.com/atapas/promiviz)

In this article, we will learn the Promise API methods using the `PromiViz` tool.

# JavaScript Promise APIs
The `Promise` object in JavaScript has six practical methods that serve several use cases.
1. Promise.all
1. Promise.any
1. Promise.race
1. Promise.allSettled
1. Promise.resolve
1. Promise.reject

These methods take one or more promises as input and return a new promise to find the result or error. The first four methods are significant when it comes to handling multiple promises.

To demonstrate examples for each of these methods, we will use three promises. Each of these promises resolves with a color name, red, green, and blue respectively,

```js
// It resolves with the value red after 1 second 
const red = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('red');
    }, 1000);
});

// It resolves with the value green after 3 seconds
const green = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('green');
    }, 3000);
});

// It resolves with the value blue after 5 seconds
const blue = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('blue');
    }, 5000);
});
``` 

# Promise.all
The method `Promise.all` executes multiple promises in parallel and returns a new promise. It waits for the execution of all the premises to complete. So, the execution time of the `Promise.all` method will be the same as the max time taken by an input promise.

Let's use our example promises(red, green, and blue) to explain the `Promise.all` method.

```js
const testAll = async () => {
    const colors = await Promise.all([red, green, blue]);
    console.log(colors);
    colors.forEach(color => {
        console.log(color);
    });
}

testAll();
```
Here we use the [async/await](https://blog.greenroots.info/javascript-async-and-await-in-plain-english-please) keywords. As the `Promise.all` method returns a new promise, we use the `await` keyword in front of it. By rule, we must use an `async` keyword for a function that uses `await` in it.

The variable `colors` is an array with all the resolved values,

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629600668570/AyjFar_yA.png?border=1,CCCCCC&auto=compress)

A few points to consider here,
- The total time needs to execute the `Promise.all` method is 5 seconds. The `blue` promise takes the max time(5 secs) to complete.
- The resulting array has the resolved value in the same order of the promises passed to the `Promise.all` method.
- If any of the input promises reject(or error out), the `Promise.all` rejects immediately. It means the rest of the input promises do not execute.

Let's try these with [Promiviz](https://promiviz.vercel.app/#). First, execute the `Promise.all` API and observe the output in the `log` window.

![promise all resolve](https://cdn.hashnode.com/res/hashnode/image/upload/v1629601224943/8LTQaRn15.png?border=1,CCCCCC&auto=compress)

Have a look at the execution time there. It took 5 seconds. That is the time the `blue` promise took to finish. Now let's reject a promise, say, the `green` one!

![promise all reject](https://cdn.hashnode.com/res/hashnode/image/upload/v1629601774794/628ncdcDA.png?border=1,CCCCCC&auto=compress)

Again, look at the time in the log window. The `Promise.all` is rejected within 3 seconds(the time `green` takes to execute). It didn't even wait for the `blue` promise to execute.

> Frequent mistake: All the input promises run parallel with the `Promise.all` method. Hence the total time to execute all the promises successfully is **NOT** the sum of their time. It is the max time taken by an input promise. In our example, it is 5 seconds(time taken by `blue`), not 9 seconds(1 + 3 + 5).

Let's move onto the following promise API method.

# Promise.any
Similar to `Promise.all`, the `any` method also takes a collection of input promises. However, it returns a new promise when `any` of the input promises is `fulfilled`.

```js
const testAny = async () => {
    const color = await Promise.any([red, green, blue]);
    console.log(color);
}

testAny();
```
In this case, the first promise, `red` takes the least time to execute and resolves. Hence the output will be red.

A few points to consider,
- If any of the input promises are rejects or errors out, the `Promise.any` method continues to execute other promises.
- If all of the input promises reject, the `Promise.any` method rejects with `AggregateError`.

Let's try these using `PromiViz`. Select the `Promise.any` API method and observe the log window.

![promise any red](https://cdn.hashnode.com/res/hashnode/image/upload/v1629603179922/51YWyI8mt.png?border=1,CCCCCC&auto=compress)

The API method took 1 second to execute the `red` promise and resolves with it. What happens when you reject the red promise. Let's do it.

![promise any green](https://cdn.hashnode.com/res/hashnode/image/upload/v1629603359503/EJ-neK4r5.png?border=1,CCCCCC&auto=compress)

Now, the `green` promise resolves as it is the next one to pick. If we now reject red and green, the API will resolve the last input promise, `blue`. Let us now reject all the promises and see what happens.

![promise any reject](https://cdn.hashnode.com/res/hashnode/image/upload/v1629603521084/sR7NB-KfD.png?border=1,CCCCCC&auto=compress)

It is `AggregateError`. Notice the time taken to execute, and it is 5 seconds, the max time taken by an input promise(blue).

# Promise.race
As the name suggests, it is the race between all the input promises, and the fastest promise wins! The `Promise.race` API method accepts a collection of input promises and returns a new promise when the fastest promise resolves.

```js
const testRace = async () => {
    const color = await Promise.race([red, green, blue]);
    console.log(color);
}

testRace();
```
In our example, the `red` promise is the clear winner. It resolves within 1 second.

A point to consider,
- If the fastest promise rejects(or error out), the `Promise.race` API method returns a rejected promise. It is a fundamental difference between the `race` method with the `any` method. The `any` method keeps trying, whereas the `race` is all about making the fastest win else all lost.

Let's understand it using `PromiViz`. Would you please run the `Promise.race` API method? We see `red` wins the race in 1 second.

![race red wiins](https://cdn.hashnode.com/res/hashnode/image/upload/v1629604403281/9tiMdjo4i.png?border=1,CCCCCC&auto=compress)

Now adjust the delays. Make it 3 seconds for `red`, 2 seconds for `green`. You should see the `green` winning the race now as it is the fastest.

![race green wins](https://cdn.hashnode.com/res/hashnode/image/upload/v1629604508138/Qx7Ws58aY.png?border=1,CCCCCC&auto=compress)

Now reject green. What do you think will happen? You have rejected the fastest promise. So, by rule, the `Promise.race` will not continue the execution of others. We will get a rejected promise that we need to handle.

![race reject fastest](https://cdn.hashnode.com/res/hashnode/image/upload/v1629604682094/dMsWhOuztw.png?border=1,CCCCCC&auto=compress)

Alright, let's move onto the following important API method.

# Promise.allSettled
The `Promise.allSettled` method is the newest inclusion to the promise API method list. Just like the methods we have seen so far, it takes an array of input promises. 

Unlike the `Promise.all` method, it doesn't reject all if any input promises reject or error out. It continues to execute and returns an array of settled promises, including their state, value, and the reason for an error.

Let's assume the red and green promises resolves successfully and the blue promise rejects due to an error. Let's run `Promise.allSettled` using these promises,

```js
const testAllSettled = async () => {
    const colors = await Promise.allSettled([red, green, blue]);
    console.log(colors);
    colors.forEach(color => {
        console.log(color);
    });
}
```
See the output,

![promise all settled](https://cdn.hashnode.com/res/hashnode/image/upload/v1629607254351/IZ_GgHEoX.png?border=1,CCCCCC&auto=compress)

It returns all the settled promises with status, value for a resolved promise, and reason for the rejection for a rejected promise. Here is the execution result of the `Promise.allSettled` API method using `PromiViz`. Please note, we reject the blue promise here.

![all-settles-pv.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629609457692/kiz0HqYVr.png?border=1,CCCCCC&auto=compress)

It took the entire 5 seconds to complete execution. It never rejected the other two promises.

# Promise.resolve and Promise.reject
The last two methods are `Promise.resolve` and `Promise.reject`. The first creates a resolved promise with a value, and the latter creates a rejected promise with an error.

```js
// It resolves with the value green after 3 seconds
const green = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('green');
    }, 3000);
});

const resolveOne = async () => {
    const result = await Promise.resolve(green);
    console.log(result);
}

resolveOne();
```
In most cases, you would probably prefer using `async/await` instead of these two methods. However, consider these methods when you create promises manually like this,

```js
new Promise(function (resolve, reject) {
  resolve(value);
}).then(/* handle it */);
```
The better and short syntax is,

```js
Promise.resolve(value).then(/* handle it */);
```
Similarly, for reject,

```js
Promise.reject(value).catch(/* handle it */);
```

Congratulations!!! You have learned about all the Promise API methods.

# Examples and Analogies
Here are some examples and analogies you may find helpful.

| Promise API Methods |     Example                       |
|-------------------------------|----------------------------------------|
|      **Promise.all**              |  I am downloading multiple files from different sources.                     |
|     **Promise.allSettled**   | I am downloading multiple files from different sources, and I am okay with whatever was downloaded successfully.                 |
|      **Promise.any**               |  I am downloading my profile image of different resolutions from several sources. I am OK with any that I get **first**.                                 |
|      **Promise.race**         |  I am downloading my profile images of different resolutions from several sources. I want to get the **fastest** one to proceed.                                 |


# So, What's Next?
We have [come a long way](https://blog.greenroots.info/series/javascript-promises) in understanding the core concepts of asynchronous programming in JavaScript. To recap, we learned about,
- [The JavaScript Promises, how to resolve and reject them](https://blog.greenroots.info/javascript-promises-explain-like-i-am-five)
- [How to tackle promises with the Promise Chain, how to handle errors](https://blog.greenroots.info/javascript-promise-chain-the-art-of-handling-promises)
- [Async/Await keywords and their togetherness with plain-old promises](https://blog.greenroots.info/javascript-async-and-await-in-plain-english-please)
- Promise API methods in this article.

Thank you for letting me know, you are enjoying the series so far. Next, we will learn about the `common mistakes` we make with promises and get better at `answering the interview questions`. Until then, you can look into the source code used in the article from this repository and try it out using [PomiViz](https://promiviz.vercel.app).

{% github atapas/promise-interview-ready no-readme %}

<hr />
I hope you enjoyed this article or found it helpful. Let's connect. Please find me on [Twitter(@tapasadhikary)](https://twitter.com/tapasadhikary), sharing thoughts, tips, and code practices. Would you please give a follow?