An Easy Way to Understand Promise in Javascript
Tags: javascript, beginners, tutorial, promise
Published: 2022-01-24 17:19:56

## Introduction

Do you feel confuse when you read `new Promise()`, `.then()`, or `.catch()`? You are not alone, and I experience the same thing. Let's start with reading the documentation itself. 

According to [MDN Web docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise), "The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value."


## Promise Object States
A promise object has three states `pending`, `fulfilled`, and `rejected`. I will use an analogy here. Same as the name, Promise, it is similar to your friend who wants to make a promise to you. After he/she states a promise with you, the only thing that you can do is wait, right? Waiting is the `pending` state in JavaScript promise. In the end, you can find out if your friend will `fulfill` your promise or `reject` to keep his promise.

![Promise States](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xzrg8q2e3tgic71bfqjt.png)

### Understanding the Promise State Flow
When we create a promise object, at first, we will get a pending state. The promise state will be changed to be `fulfilled` if the function inside the promise calls the `resolve` callback. However, if the function inside promise calls `reject` callback, the state will be changed to be `rejected`

![Promise Flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t24c294i6z6l5bseuqo1.png)

Try to run this code in your browser console to see how the promise state is changed from pending to fulfilled.
```js
  const newPromise = new Promise((resolve) => {
    setTimeout(() => resolve('Success'), 2000);
  });
  console.log("[After promise initialization]", newPromise);

  setTimeout(() => console.log("[After resolve callback run]", newPromise), 2000);
```

## Promise Object Methods
After we understand the basic concept of promise states, we can move forward with promise methods. We just saw the state was changing from `pending` to `fulfilled`, but we didn't access the result. That's the reason why we need the promise methods.

![Promise Method](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hn8tgbrqin7i8tt0kjkg.png) 
If we take a look inside the promise prototype, we can find out that promise has a constructor method, and three prototype methods, which are `.then()`, `.catch()`, `.finally()`. _Therefore, whenever you see those methods are being called, you can assume that the variable before the method is a promise object._

### [Constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise)
The promise constructor requires a callback function to be sent as a parameter. The callback function has two function parameters, and the parameter name convention is `resolve` and `reject`. 
`resolve` function will cause the state change to be `fulfilled`. On the other hand, `reject` will change the state to be `rejected`. Both functions has one parameter to return the value.
```js
  const fulfilledPromise = new Promise((resolve, reject) => {
    resolve("Success")
  });
  const rejectedPromise = new Promise((resolve, reject) => {
    reject("Fail")
  });
```

### [.then()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)
Alright, the most popular promise method. You probably see this method everywhere. `.then()` has two optional parameters that are `onFulfilled` and `onRejected`. I guess you can understand it easily. The first parameter will handle the result of the promise if the state is `fulfilled`, and the second parameter is for handling `rejected` state.

```js
// ...
newPromise.then(
  (fulfilledResult) => {
    console.log(fulfilledResult);
  },
  (rejectedResult) => {
    console.log(rejectedResult);
  }
);
```
-- OR --
```js
// ...
function onFulfilled(result) {
  console.log(result);
}
function onRejected(error) {
  console.log(error);
}
newPromise.then(onFulfilled, onRejected);
```
In fact, in my experience, I don't use the second parameter because we have another method to handle the `rejected` state, which we will discuss in the next section.

### [.catch()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch)
With this method, the `rejected` state will directly be handled. It's similar like `.then()`, but `.catch()` is only has one callback function parameter.

```js
newPromise.catch((error) => {
  console.log(error);
});
```

Example of chaining `.catch()` with `then()`.
```js
// ...
myPromise.then(result => console.log(result))
   .catch(error => console.log(error));
```


### [.finally()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally)
Finally, it is `.finally()`, the last promise object method. `.then()` same like `.catch` that it only has one callback function.In addition, It will be called when the promise is settled whether the state is `fulfilled` or `rejected`. However, the `.finally()` callback function doesn't have any parameter.

```js
// ..
newPromise.finally(() => {
  console.log('Done');
});
```

`.then()`, `.catch()`, `.finally()`, and Promise constructor return a promise object. That's why you might see this chaining method.

```js
fetch('https://api.zippopotam.us/us/90210')
  .then((res) => res.json())
  .then((data) => console.log(data))
  .catch((error) => console.log(error))
  .finally(() => console.log('done'));
```

## Async and Await
In the beginning, I was confused with `fetch()`. Why does `fetch` always need double `.then` like the previous example. After I read the [fetch ](https://developer.mozilla.org/en-US/docs/Web/API/fetch#return_value) and [response.json()](https://developer.mozilla.org/en-US/docs/Web/API/Response/json#return_value) documentation meticulously, I realized that those return promise objects as well. That's why we need `.then()`

There is another way if we don't want to use chaining `.then()`. Thanks to async and await. In order to activate await, we must call await inside the async function. This is an example.

```js
async function fetchData() {
  const response = await fetch('https://api.zippopotam.us/us/90210');
  const data = await response.json();
}
```

If I translate to our language, await is like waiting for our friend to answer his promise. Therefore, using await we can get the answer before we execute the next line of code.

Try to run the first code snippet in your browser console, and compare it with the second code. The first code will return a promise, but in the second one, you can get the value.

```js
async function fetchData() {
  const response = fetch('https://api.zippopotam.us/us/90210');
  console.log(response);
  const data = response.json();
  console.log(data);
}

fetchData();
```
```js
async function fetchData2() {
  const response = await fetch('https://api.zippopotam.us/us/90210');
  console.log(response);
  const data = await response.json();
  console.log(data);
}

fetchData2();
```

## Conclusion
I wish I can understand about promise in detail at first. It will be so helpful to read the chaining method. Other Promise Methods might be helpful in our code, and I might write them in another post. I hope this promise blog could help you to work around with promise.