Modern JavaScript: Promise
Tags: javascript, tutorial
Published: 2022-03-26 10:24:45

## Table of contents
1. [Introduction](#Introduction)
2. [Promise](#Promise)
3. [First Examples](#First Examples)
4. [Handling Promise](#Handling Promise)
 1. [then()](#then())
 2. [catch()](#catch())
 3. [finally()](#finally())
 4. [Chaining](#Chaining)
5. [Advanced Usage](#Advanced Usage)
 1. [Server Request](#Server Request)
 2. [Multiple Requests](#Multiple Requests)
 3. [First to settle](#First to settle)
 4. [First to fulfill](#First to fulfill)
6. [Outro](#Outro)

## Introduction

When it comes to JavaScript it executes code one line after another so next line of code will not start it's execution up until previous one have finished

But what if required operation takes too much time? Should we freeze whole application's execution waiting for result? Obviously, not

Most common and easily understandable example is request to some server. You never know how much time exactly there is needed to receive response. It may take few dozens of milliseconds or few seconds

And while waiting for response we still want our application to be responsive, usable and even let customer know about making server request like through showing some sort of loader animation

![small loader image that is used to let customer know that something is being loaded](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/560jncweiq9mov0wshft.png)

In addition, once application receives response it should process it somehow so we also need a way to tell the program how it should treat data it is going to receive in future and we are not able to know when exactly

Basically, we want to be able to tell our program such thing:

> In **background**, without blocking whole execution process, make this request, wait for the response and once received perform given set of commands

But how can we achieve such kind of functionality if currently we are aware that JavaScript executes all of the code in strict sequence?

## Promise

In short, Promise allows performing operations asynchronously

The concept of Promise is pretty straightforward:

> Give it piece of code you want to execute asynchronously and specify in what case Promise should fulfil successfully and vice versa

To understand principle of Promise better before diving into examples few theory concepts have to be discussed

First of all, when we create Promise with code to process asynchronously, we should pass this code in form of callback.

> **Callback** - function passed as an argument for another function that is going to be executed at some specific point of latter function execution

Callback that is being passed to promise is called **executor**

> **Executor** -  callback function, invoked by Promise with two arguments being passed: **resolve** and **reject**

> **resolve** - callback function that should be called when operation inside of Promise finishes successfully. Usually, accepts one parameter - result of operation performed inside of **executor**

> **reject** - callback function that should be called in case when error happens during **executor's** code processing

In terms of making server request we would call **resolve** with response as an argument right after receiving it to proceed with it's further processing

## First Examples

When we need to create promise we have to use constructor of **Promise** class with keyword new. Basically, we create instance of class **Promise**

As it was mentioned earlier, to create promise we should pass **executor**

Simplest example of how to create new Promise:

```javascript
new Promise((resolve, reject) => {})
```

Currently, our promise does nothing. To actually see, how promise executes code in async manner let me show you next example

{% runkit %}
new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('in promise');
    }, 1000)
})

console.log('after promise')
{% endrunkit %} 

You can run this code right in browser or anywhere else to see what happens. First message to console we receive is 'after promise' and only after 1 second message 'in promise' is being printed out. 

Function `setTimeout` allows to delay execution of code and I am going to use this feature to demonstrate more capabilities of promises.

## Handling Promise

Basically, promise can be fulfilled or rejected. If code inside of an executor processed well, callback **resolve** is being invoked and promise starts fulfilling. In opposite case, callback **reject** is called and rejection happens.

Promise gives us, developers, possibility to control what has to be done in case of promise fulfilment and rejection.

Object of Promise provides two methods for such thing: `then` and `catch`. Both accept callback

### then()

To understand better, let's firstly set up our playground. First of all, I will create promise and save it to constant. Inside of an executor I will utilize `setTimeout` to postpone invocation of `resolve` function up to 1 second. To `resolve` I will pass string 'Hello Promise'

```javascript
const ourPromise = new Promise((resolve, reject) => {
    setTimeout(() => resolve('Hello Promise'), 1000);
});
```

Now, let's use `.then()` for the first time. I know that promise will pass string to callback on fulfilling, so let's print received message

```javascript
ourPromise
    .then((message) => console.log(message));
```

{% runkit %}
const ourPromise = new Promise((resolve, reject) => {
    setTimeout(() => resolve('Hello Promise'), 1000);
});

ourPromise
    .then((message) => console.log(message));

console.log('after promise');
{% endrunkit %}

If you run code above you can see that message 'after promise' is being printed first, just like last time. Only difference is that message 'Hello Promise' is being printed in callback passed to `.then()` as an argument.

### catch()

In case if **executor**'s code fails, Promise should be rejected by **reject** invocation. To actually handle Promise's rejection, you should pass callback to `.catch()` method of Promise instance. Usually, error being passed as an argument.

Let's consider next code example:


{% runkit %}
const ourPromise = new Promise((resolve, reject) => {
    setTimeout(() => reject('Rejecting Promise'), 1000);
});

ourPromise
    .catch((message) => console.log(message));

console.log('after promise');
{% endrunkit %}

It's almost the same as previous one, but we call **reject** instead of **resolve** and replace **.then()** with **.catch()**. As a result we get the same output in console.

### finally()

It's pretty common occasion when you need to perform code on Promise's settlement despite the outcome. To avoid duplication of logic in `.then` and `.catch` methods there is `.finally`.

Callback passed to method `.finally` is going to be executed in any case: either Promise resolved successfully or was rejected

{% runkit %}
const ourPromise = new Promise(
  (resolve, reject) => {
    if (Math.random() > 0.5) {
      reject('Rejecting');
    }
    
    resolve('Resolving');
  }
);

ourPromise
  .then(msg => console.log(msg))
  .catch(err => console.log(err))
  .finally(() => console.log('Final action'));
{% endrunkit %}

Important note

> callback passed to `finally` does not accept any arguments

### Chaining

Methods `.then`, `.catch` and `.finally` return promise itself, so they can be chained. That's what makes working with Promises neat and concise. Try to run below example multiple times and see how in different cases different callbacks are being invoked

{% runkit %}
const ourPromise = new Promise(
  (resolve, reject) => {
    if (Math.random() > 0.5) {
      reject('Rejecting');
    }
    
    resolve('Resolving');
  }
);

ourPromise
  .then(msg => console.log(msg))
  .catch(err => console.log(err))
  .finally(() => console.log('final action'));
{% endrunkit %}

Another important thing is that you are not limited to one `.then` invocation, for example. There can be occasions when you receive another promise while handling previous one and to process new promise we can just return it and use `.then` again. Let me just show you

{% runkit %}
const ourPromise = new Promise(
  (resolve, reject) => {
    if (Math.random() > 0.5) {
      reject('Rejecting');
    }
    
    resolve('Resolving');
  }
);

ourPromise
  .then(msg => msg + ' x2')
  .then(msg => console.log(msg))
  .catch(err => console.log(err))
  .finally(() => console.log('final action'));
{% endrunkit %}

As you can see from first callback I returned original message plus some extra characters. Value, returned from previous callback is being passed to next one.

Now let me show example with multiple Promises:

{% runkit %}
const ourPromise = new Promise(
  (resolve, reject) => {
    if (Math.random() > 0.5) {
      reject('Rejecting');
    }
    
    resolve('Resolving');
  }
);

ourPromise
  .then(
     msg => new Promise((resolve) => resolve('Another Promise'))
  )
  .then(msg => console.log(msg))
  .catch(err => console.log(err))
  .finally(() => console.log('final action'));
{% endrunkit %}

If you run code above and first promise is going to be resolved then you will see that message we passed to **resolve** function inside of our second Promise successfully got to callback we passed to our second `.then`. This way we can handle multiple consecutive Promises in beautiful and convenient way

## Advanced Usage

### Server Request

Modern JS libraries and APIs for making and handling requests to server are built around Promise. Client side [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/fetch) is built around Promise

Let me show you one example using quite well-known library `axios`

{% runkit %}
const axios = require('axios');

axios.get('https://jsonplaceholder.typicode.com/users')
    .then(res => console.log(res.data));

console.log('Something after request');
{% endrunkit %}

As you can see, we were able to perform request and process it response without blocking execution process

### Multiple Requests

Sometimes there is need to perform multiple requests simultaneously. Specifically for this reason one of the methods provided by Promise can be utilised.

{% runkit %}
const axios = require('axios');

const requests = [
    axios.get('https://jsonplaceholder.typicode.com/users'),
    axios.get('https://jsonplaceholder.typicode.com/posts'),
    axios.get('https://jsonplaceholder.typicode.com/comments')
]

Promise.all(requests)
    .then(res => console.log(res))
{% endrunkit %}

`Promise.all()` accepts iterable object like array, for instance, with promises we need to wait for. Once all Promises are resolved or at least one is rejected, then result of method `all` which is Promise itself is resolved or rejected

### First to settle

If you are waiting on multiple promises and you need to perform some action once one of them resolves or rejects there is method for that: `Promise.race`

There is an example:

{% runkit %}
const ourPromise = new Promise(
  (resolve, reject) => {
    setTimeout(() => {
        if (Math.random() > 0.5) {
      reject('Rejecting 1');
    }
    
    resolve('Resolving 1');
    }, Math.floor(Math.random() * 1000))
  }
);

const ourPromise2 = new Promise(
  (resolve, reject) => {
    setTimeout(() => {
        if (Math.random() > 0.5) {
      reject('Rejecting 2');
    }
    
    resolve('Resolving 2');
    }, Math.floor(Math.random() * 1000))
  }
);

Promise.race([ourPromise, ourPromise2])
    .then(res => console.log(res))
    .catch(res => console.log(res));
{% endrunkit %}

### First to fulfill

If you want to perform action once first among many promises fulfils there is solution for you as well: `Promise.any`. Be aware that `Promise.any` exists in Node since version 15 so you might need to change the version of runner below

{% runkit %}
const ourPromise = new Promise(
  (resolve, reject) => {
    setTimeout(() => {
        if (Math.random() > 0.5) {
      reject('Rejecting 1');
    }
    
    resolve('Resolving 1');
    }, Math.floor(Math.random() * 1000))
  }
);

const ourPromise2 = new Promise(
  (resolve, reject) => {
    setTimeout(() => {
        if (Math.random() > 0.5) {
      reject('Rejecting 2');
    }
    
    resolve('Resolving 2');
    }, Math.floor(Math.random() * 1000))
  }
);

Promise.any([ourPromise, ourPromise2])
    .then(res => console.log(res))
    .catch(res => console.log(res));
{% endrunkit %}

## Outro

That's it for today. Hope you enjoyed this little article.

Don't hesitate to leave a comment, I would appreciate it.

Have a nice day :)