Mastering Javascript Promises
Tags: javascript, promise
Published: 2021-05-08 10:30:57

---
title: Mastering Javascript Promises
published: true
description: A detailed guide to javascript promises
tags: javascript, promise, 
---

A promise is an object that represents the eventual completion or failure of an asynchronous operation. It simply means that we can write asynchronous code using a promise, just like we do with a callback function but with some ease and most importantly without getting into the trap of callback hell 😉.

### What is a Promise?

A promise is a construct to execute code asynchronously, which may be in one of the following states at a given point in time.

- *Pending*:- Initial state, neither fulfilled nor rejected.
- *Fulfilled*:- Successful execution, returns value via `then` handler.
- *Rejected*:- Failure, can be handled using a `catch` handler.


```javascript
return new Promise((resolve, reject) => {
  setTimeout(() => resolve("done"), 1000);
})
```


The above code uses a `setTimeout` that resolves the promise with a value "done" in this case in one second. 

Consider the following code that fetches GitHub user information using promise.


```javascript

 function fetchUser(username) {
  fetch('https://api.github.com/users/' + username)
  .then(response => response.json())
  .then( data => {
    const str = JSON.stringify(data, undefined, 2);
    document.getElementById('content').innerHTML = str;
  })
  .catch( error => console.error(error));
}

fetchUser('saroj990');

```

{% codepen https://codepen.io/saroj990/pen/GRrwmzV %}

Initially, promises were not baked into native Javascript(*es6 got promise built natively into javascript*) rather were available via third-party libraries like `Q`, `BlueBird`. So all the libraries that had been developed back in those days probably had used a dedicated separate promise library for achieving asynchronicity.

### How to Construct a Promise?

We just need to create a new instance of `Promise`, which receives `resolve` and `reject` as arguments and when we want to return a value, we use `resolve` and `reject` is used to reject the promise with an error.

```javascript

function doAsync() {
  return new Promise((resolve, reject) => {
    const number =  Math.ceil(Math.random() * 10);
    if (number % 2 === 0) {
      setTimeout(() => resolve("even"), 2000);
    } else {
      setTimeout(() => reject("odd"), 2000);
    }
  });
}

```
We are sort of calculating a random number between 1 to 10. If the number turns out to be an even number, we resolve the promise. If the value is odd, we reject the promise.

Here is how we can execute a promise.

```javascript
doAsync()
  .then((value) => {
    // success handler
  })
  .catch(err => {
    //log error
  });

```
When we resolve a promise then the value is received by the `then` handler and in case of rejection, the error is caught by the `catch` handler.

### Why do we need a Promise?

If you already know this👌👌. But I will keep it short here so that we don't get deviated from our topic. 

Promises were introduced to mitigate the problems that emerged by callback hell. 

### Callback Hell

Callbacks are nothing but functions that can be passed into another function as an argument, and when there are more callbacks nested one inside another, the code becomes really hard to understand. 


```javascript
function getUser(id, profile, callback) {
  User.find(id, function (err, user) {
    if(err) {
      callback(err);
    } else {
      user.profile = profile;
      user.save(function(err, user) {
        if(err) { 
          callback(err)
        } else {
          Subscription.findSubscription(id, function(err, subscription) {
            if(err) {
              callback(err) ;
            } else {
              user.subscription = subscription;
              callback(subscription);
            }
          });
        }
      });
    }
  });
}
```

The above code looks bad and not expressive at all, the situation becomes really worse when another level of nesting comes into the picture.

Let's re-factor the same code with a promise.

```javascript
function getUser(id, profile) {
  const currentUser = {};
  return new Promise((resolve, reject) => {
    User
      .find(id)
      .then((user) => {
        currentUser = user;
        currentUser.profile = profile })
      .then(() => Subscription.find(id))
      .then(subscription => {
        currentUser.subscription = subscription;
        return resolve(currentUser)
      })
      .catch(err => reject(err))
  })

}
```


Now the code looks really neat👌👌. Isn't it ?. So using a promise has an added advantage as it makes your code more readable and easy to understand.


### Chaining a Promise

Promise chaining is a pattern where the output of one promise becomes an input for another. 

Here is an example where we are kind of trying to book an appointment.

```javascript

Appointment
.findSlot(time)
.then(slot => BookAnAppointment(slot.id))
.then(appointment => FinishPayment(appointment.id))
.then(payment => getInvoice(payment.id))
.then(invoice => console.log(invoice))
.catch(err => console.log(err));
```
### Parallel executions

There are situations where promises need to be executed independently and have no relation with other promises.

There is a `Promise.all` construct in `Javascript` promise that executes promises in parallel for achieving this.

```javascript
// marks a user in-active
function markInActive(id) {
  return User
  .findById(id)
  .then(user => {
    user.active = false;
    //returns a promise
    return user.save();
  });
}

// collect the promises into an array
const promises = []
for (let i=0; i < ids.length; i++) {
  promises.push(markInActive(ids[i]));
}

//execute them altogether
Promise.all(promises)
.then(result => console.log(result))
.catch(error => console.log(error));

```

You might be wondering what is the difference between chaining a promise vs parallel execution. Well, let's evaluate it with an example.


```javascript

function promiseOne() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve('promiseOne'), 1000);
  })
}

function promiseTwo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve('promiseTwo'), 1000);
  })
}

function promiseThree() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve('promiseThree'), 1000);
  })
}
```

When the promises are executed in a chain, the second promise starts its execution only when the first promise finishes.

```javascript
promiseOne()
.then((res1) => { 
  console.log(res1);
  return promiseTwo() 
})
.then((res2) => {
  console.log(res2);
  return promiseThree();
}).then(res3 => {
  console.log(res3);
})
.catch(err => console.log(err));

/*
output
promiseOne
promiseTwo
promiseThree
each promise takes 1sec to execute
effective time: 3sec
*/
```
Now let's try the same code with `Promise.all`, parallel execution allows all the promises to run in parallel at the same time.

```javascript

Promise.all([ promiseOne(), promiseTwo(), promiseThree()])
  .then(result => console.log(result))
  .catch(err => console.log(err));


/*
output: 
[ 'promiseOne', 'promiseTwo', 'promiseThree' ]
all the promises get executed at the same time
so effective time: 1sec
*/
```

### Converting a Callback to a Promise

If you've followed along up to this point, you should know how to convert a callback to a promise. First off, we need to know why do we need to convert a callback to a promise.

There are times where certain library functions don't have their promise variant methods(i doubt almost all libraries ship their promise interface method these days), but you want to use it as a promise.


```javascript
function saveUser(payload) {
  return new Promise((resolve, reject) => {
    User.save(payload, function(err, user) {
      if(err) return reject(err);
      return resolve(user);
    });
  });
}
```


The `User` model `save` method is a callback method, we just wrapped it inside a new `Promise` construct with resolve and reject. if an error happens, we reject the promise with error, else we just resolve it with user information.


### Error Handling(catch/finally)

Although creating a promise is fun, it will be useless if we don't handle errors that may occur while executing a promise. To achieve this, we have the `catch` handler at our disposal, which receives the error object as an argument to the handler function.

Here is a sample code that explicitly throws an error and it is handled by the catch block.

```javascript
new Promise((resolve, reject) => {
  reject("some error happened!");
}).catch(err => console.log(err));

```

We can also throw an explicit error from the promise and it is exactly the same as above.

```javascript
new Promise((resolve, reject) => {
  throw new Error("some error occurred!!")
}).catch(err => console.log(err));
```

A catch handler can handle both synchronous or asynchronous occurred inside a program.

What we just saw in the above example where we deliberately raised an error. Now let's take look at another example where the error is asynchronous.


```javascript
const prom1 = () => new Promise((resolve, reject) =>  {
  setTimeout(() => {
    //rejects after 2sec
    return reject("rejected prom1 promise");
  }, 2000)
});

new Promise((resolve, reject) => resolve("done"))
  .then(res => prom1())
  .catch(err => console.log(err))
```
Here the first method `prom1` rejects the promise asynchronously(just mimicked with a setTimeout😉).

A `then` and `catch` block can be nested one after another like following.

```javascript

new Promise((resolve, reject) => {
  resolve("done")
}).then(res => {
  console.log("response is : ", res);
  throw new Error("error after the first promise resolved");  // synchronous error
}).catch(err => {
  console.log("error caught in catch handler", err);
  return "You can rest now"; 
//simply pass the value to next level
}).then(res => console.log(res))
.catch(err => console.log(err)); 
// prints "you can rest now"


```
Usually, people just use one catch block appended to the end of the promise, and whatever error occurs just get caught by the catch handler.

#### Finally

Another important part of a promise is the `finally` block, which gets executed no matter a promise is successful or rejected.

```javascript

new Promise((resolve, reject) => resolve("done"))
.then(res => console.log(res))
.catch(err => console.log("I can catch fish too. :)"))
.finally(() => console.log("I am inevitable, I will always get a chance to execute"))

```

Let me explain it in a better way with an example so that we can really get the reason behind using a `finally` block.

```javascript
isLoading = true;
fetchUser(id)
.then(user => subscribeToNewsLetter(user.id))
.then(response => {
  console.log("subscribed to news letter", response);
  // set loader to false once the user info is retrieved
  isLoading = false;
})
.catch(err => { 
  console.log(err);
  // in case of error
  isLoading = false;
});

``` 

We are sort of using a `isLoading` variable to track when an async operation starts and when it is finished so that we can display a loader and hide it when we get the response.

Needless to say, we are setting the `isLoading` to `false` in two different places.

* inside the success handler `then`
* inside the error handler. This is because if any error happens we don't want the loader to continue forever. Do you? 😂😂

This implementation works but not efficient and is repetitive. We can handle it better with a `finally` block.

```javascript
isLoading = true;
fetchUser(id)
.then(user => subscribeToNewsLetter(user.id))
.then(response => console.log("subscribed to news letter", response))
.catch(err => console.log(err))
.finally(() => isLoading = false);

```
`Finally` block gets executed no matter what happens to a promise, so this can be used as a place where we can do some clean-ups and stuff like closing `DB`, `socket` connections, etc.

If you have made up this far, congrats!!😁👍. If you feel like that this article has helped you understand Javascript Promises, don't hesitate to show your love by liking this post. 

If you feel like something could be improved in the article, please do add a comment. I would really appreciate it.