An Easy Way to Understand Promise in Javascript

Photo by Ryan Franco on Unsplash

An Easy Way to Understand Promise in Javascript

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, "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

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

Try to run this code in your browser console to see how the promise state is changed from pending to fulfilled.

  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 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

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.

  const fulfilledPromise = new Promise((resolve, reject) => {
    resolve("Success")
  });
  const rejectedPromise = new Promise((resolve, reject) => {
    reject("Fail")
  });

.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.

// ...
newPromise.then(
  (fulfilledResult) => {
    console.log(fulfilledResult);
  },
  (rejectedResult) => {
    console.log(rejectedResult);
  }
);

-- OR --

// ...
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()

With this method, the rejected state will directly be handled. It's similar like .then(), but .catch() is only has one callback function parameter.

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

Example of chaining .catch() with then().

// ...
myPromise.then(result => console.log(result))
   .catch(error => console.log(error));

.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.

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

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

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 and response.json() 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.

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.

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

fetchData();
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.