Promises in JavaScript
Tags: beginners, javascript
Published: 2021-06-20 07:14:11

Hope you had a great break before continuing the series! 

In this article, we would cover `Promises`. If you haven't read the previous article ([Intro to Asynchronous JS](https://dev.to/mehmehmehlol/intro-to-asynchronous-javascript-g9e)), I highly recommend you to first read it before coming back to this article, as it builds an important foundation for this article.

<img src="https://i.pinimg.com/originals/c9/0a/98/c90a989fcf6b4d55d44ebd367705fc38.gif" alt="coffee dive" />

There are 4 parts in this series:
1. Intro to Asynchronous JS 
2. `Promises` (this article)
3. More `Promises` 
4. `async/await`

## Introduction 

`Promises` was introduced in ES6 to simplify asynchronous programming. 

I would divide this article into the following sections:
- Why was `Promises` introduced? (Spoiler Alert: Trouble with callbacks)
- Promise Terminology
- Basic Promise usage
- Promise Consumer: `then`, `catch`, `finally`

In the next article, we'll cover: 
- Chaining Promise
- Fulfilling multiple Promises

## Before Promises: Old-style Callbacks 

Before the introduction of `Promises` in ES6, asynchronous was commonly handled with **callbacks** (calling a function within another function). This is important to know before diving into `Promises`. 

Let's see some callback example. Imagine you are ordering Starbucks coffee on a Monday morning and you are feeling cranky. Unfortunately, you don't just get your coffee with a snap.
<img src="https://media1.giphy.com/media/iIFS20pNoCg1EEVodC/giphy.gif" alt="Thanos snap"/>

You have to first decide what kind of coffee you want, then you place your order with the barista, then you get your coffee, last but not least, 
<img src="https://www.memesmonkey.com/images/memesmonkey/7c/7cc3990d5ba24d64dc252f38c26512e2.jpeg" alt="monkey sipping meme" />

Here's how the callback's going to look like (reference to <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises">MDN doc on Promise</a>):

```javascript
chooseCoffee(function(order) {
  placeOrder(order, function(coffee) {
    drinkCoffee(coffee);
  }, failureCallback);
}, failureCallback);
``` 
As you can see, it's very messy-looking! This is what is often referred to as "<a href="http://callbackhell.com/">callback-hell</a>". `Promises` allow these kinds of nested callbacks to be re-expressed as **Promise chain**, which we would cover more in the next article. 

In the following section, we would first cover the terminology, then we'll dive into the basic Promise usage using the callback functions we saw in the series. 

## Promise Terminology

Here's the basic syntax of `Promise`:
```javascript
let promise = new Promise(function(resolve, reject) {
  // executor
});
```
The arguments `resolve` and `reject` are the two callbacks provided by JavaScript.

Here are the three states in a promise you need to know:
1. **pending**: when a promise is created, it is neither in success or failure state.
2. **resolved**: when a promise returns, it is said to be **resolved**.
3. **fulfilled**: when a promise is successfully resolved. It returns a value, which can be accessed by chaining a `.then` block onto the end of the promise chain (will discuss this later in the article)
4. **rejected**: when a promise is unsuccessfully resolved. It returns a reason, an error message why it is rejected (`Error: Error here`). This can be accessed by chaining a `.catch` block onto the end of the promise chain.

Here's a more visual graph from [javascript.info](https://javascript.info/promise-basics)
![Promise graph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51xpczm8qnorssbxm7zk.png)

## Basic Promise usage

In a promise, there can be only one result or error. So let's say we have this Promise function:

```javascript
let promise = new Promise(function(resolve, reject) {
  resolve("done");
  reject(new Error("Not okay!")); // ignored
})
```

The result will immediately show "done" and the error will be ignored.

This is the easy version. This is what you can expect how a promise will look like:
```javascript
  let example = () => {
   return new Promise(function(resolve, reject) => {
     let value = function1();
     if (job success) {
       resolve(value);
     } else (job unsuccessful) {
       reject(console.log("something's wrong!! :("));
     }
   }).then(function(value)) {
     // success
     return nextFunction(value);
   }).catch(rejectFunction);
  }
```

Okay, it's getting a lot and we've got some new friends in the above function. What's `.then` and `.catch`? We will get to them in the next section, but just a quick breakdown from above:
- As a promise is created, if the function is passed successfully, the promise will be resolved.
- On the other hand, if the function is passed unsuccessfully, the promise will be rejected and "something's wrong!! :(" will be printed on the console.

This is all you need to know for now! Let's move to our consumers in `Promises`!

## Consumers: `.then`, `.catch`, `.finally`

A Promise object serves as a connection between the executor (you know the `resolve`, `reject`) and the consuming functions. Consuming functions can be registered with methods: `then`, `catch`, `finally` (which you've already seen `.then` and `.catch` in the previous section!).

Here's the promise cycle:
1️⃣ A promise is created (State: Pending)
2️⃣ a 
👉🏻 A promise is **resolved** (State: resolved)
👉🏻 Promise chain with `.then`
2️⃣ b 
👉🏻 A promise is **rejected** (State: rejected)
👉🏻 `.catch` to handle errors
3️⃣ `.finally` to give the final result of the promise 💯

### `.then`

As I learned how to use these consumer methods, I like to think `.then` as... *then* what would you like to do after we **resolved** the promise?

Consider `.then` is similar to `AddEventListener()`. It doesn't run until an event occurs (i.e. the promise is resolved).

 ```javascript
let promise = new Promise(function(resolve, reject) {
  setTimeOut(() => resolve("done!!"), 1000);
});

promise.then(
  // shows "done!" in console after 1 second
  result => console.log(result) 
);
```
Note: You can show errors using `.then`.

### `.catch`: Error Handling

Promises is not always resolved, but there are cases where promises is rejected. Therefore `.catch` is here to *catch* errors. 

Here's how we remember:
- `.then` works when a promise is **resolved**.
- `.catch` works when a promise is **rejected**.

If we are interested in seeing errors, here's how we use `.catch`:
```javascript
let promise = new Promise(function(resolve, reject) {
  setTimeOut(() => reject(new Error("NO!")), 1000);
});

// shows the error after 1 second
promise.catch(result => console.log(result));
```
Feel free to copy the code above to your terminal/Chrome DevTool (if you are using Chrome). You should see the following:
![.catch demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t3vgw4h232k8qoia3e55.png)

Note: `.then(null, func)` is the same as `.catch(func)`

### `.finally`

`.finally`, which is introduced in ES2018, is like a decent closure for the promise. Think of it like *finally* we are done and it's time to disclose the *final* result. In other words, it works no matter the promise is resolved or rejected. 


`.finally` is a good handler for performing cleanup, like stopping the loading indicator. 

If a promise is resolved:
```javascript
let promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve("done!"), 2000);
})

promise.finally(() => console.log("Promise ready"));
promise.then(result => console.log(result)); 
``` 

Quick Demo:
![resolved promise finally demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uafpfxdtw1jo4dpmoomx.gif)

If a promise is rejected:
```javascript
let promise = new Promise((resolve, reject) => {
  throw new Error("error");
})
promise.finally(() => console.log("Promise ready"))
promise.catch(err => console.log(err)); 
``` 

Quick Demo:
![rejected promise finally demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8fkuz5r37bvcanaqmoai.gif)
 
Well let's put all these together, shall we?

Let's apply our new knowledge to our Monday morning coffee from the callback-hell section, but I will add one more condition is that we will only buy coffee if our mood rates lower than or equal to 5 (out of 10):
```javascript
function orderCoffee() {
  return new Promise((resolve, reject) => {
    let rating = Math.random() * 10;
    // this is only a reference so that 
    // we know what the rate of mood is
    console.log(rating);
    if (rating > 5) {
      resolve("I AM FEELING GREAT!");
    } else {
      reject(new Error("We are going to Starbucks..."));
    }
  });
}

orderCoffee()
  .then(mood => console.log(mood))
  .catch(err => console.log(err))
  .finally(() => console.log("Decision's been made!"));
```
(Code reference from MDN's [Promise.prototype.finally()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally))


If the mood rates higher than 5 (i.e. the promise is resolved) (You can see the number on the first line after the handlers):
![Resolved Promise Coffee Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9l5kwngkyglo13cmvcvm.gif)

If the mood rates lower than or equal to 5 (i.e. the promise is rejected):
![Rejected Promise Coffee Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/68urqlacu8250iyyekyi.gif)
 
Feel free to copy the code above on your ChromeDevTool/terminal to play around!!

A quick recap on this section:
- If a promise is resolved, `.then` will take over the rest.
- If a promise is rejected, `.catch` will take over and return the error.
- `.finally` is good for performing cleanup as it works no matter the promise is resolved and rejected.

---

Alright, these are the basics of Promises! In the next article, we'll talk more about chaining promises and fetching multiple promises! 

Here's a quick glimpse using Promise chain from our callback example:
```javascript
chooseCoffee()
.then(order => placeOrder(order))
.then(coffee => drinkCoffee(coffee))
.catch(failureCallback);
```

## Resources: 
🌟 Highly Recommend: [Promise](https://javascript.info/promise-basics) (javascript.info)
🌟 Eloquent JavaScript Chapter 11: Asynchronous Programming
🌟 JavaScript The Definitive Guide by David Flanagan (7th Edition) Chapter 13.2: Promises (Pg. 346 - 367) ([Amazon](https://www.amazon.com/_/dp/1491952024?tag=oreilly20-20))
🌟 [Graceful asynchronous programming with Promises](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises) (MDN)
🌟 [JavaScript Async/Await Tutorial – Learn Callbacks, Promises, and Async/Await in JS by Making Ice Cream 🍧🍨🍦](https://www.freecodecamp.org/news/javascript-async-await-tutorial-learn-callbacks-promises-async-await-by-making-icecream/) (FreeCodeCamp)
🌟 [How To Implement Promises in JavaScript?](https://www.edureka.co/blog/how-to-implement-promises-in-javascript/#ConsumersinPromisesinthen())

🦄 If you are looking for more explanation (or a different way of explaining) on this concept, I'd like to recommend my friend, Arpita Pandya's article:
[JavaScript Promises](https://arpitapandya.medium.com/javascript-promises-dc4615e487b)