DEV Community

Sachin Sarawgi
Sachin Sarawgi

Posted on

Promise to Learn Promises in JavaScript

Stuck with callback hell, here is the Promise Object which promises to solve the Callback Function Problems.

JavaScript is synchronous language by nature. The asynchronous functions like a callback, promise are internal to the JavaScript engine which is part of the browser. For example, Chrome uses the Google V8 JavaScript engine. Because of this, all the functionality related to asynchronous is developed in external libraries.

In JS we can solve asynchronous features using Callback, Promises, Async Await.

Before we start please read about Callback Deep Dive in JavaScript.

Topics Covered

  • What are Promises
  • Which Use Case Solved By Promises
  • Problem With Callback Functions, The Callback Hell
  • How To Write Promise Producer Code
  • Promise Object Properties
  • How To Write Promise Consumer Code
  • Solving Callback Hell With Promises
  • ### What are Promises

Promises are JavaScript object introduced in ES6 onwards, which handles the asynchronous result of an operation.

It consists of producer code which produces a result/response after some duration of time from the time when it’s called. The other part is called consumer code which consumes the result/response generated by producer code.

Which Use Case Solved By Promises

  1. Suppose we are calling an API, and that API response time is high. That means for processing the response we have to wait till we get the response.
  2. Suppose we are loading a JavaScript file in a function, and in the next line we are calling a function that is declared inside that script.
  3. Suppose you want to call another API once you get the first response, another one after you get a second API response. This type of requirement is called callback chaining.

If you know Callback functionality would seem similar based on the above scenario, indeed it is but there are some major problems with a Callback function which is handled by Promise very gracefully. One of them is called Callback Hell, discussed in the next section_._

Problem With Callback Functions, The Callback Hell

A callback function easy to understand when we don’t have callback chaining or callback after callback. Let’s take a simple example, where there is only one callback function

function getAPIRequest(_callbackOnSuccess_, _callbackOnError_){  var getReq = new XMLHttpRequest();  
  getReq.open("GET", "https://reqres.in/api/users?page=2");  
  getReq.send();  
  getReq.onload = () => {  
    alert("The response is " + request.response);  
  }  
}
getAPIRequest();

In the above code, we called a GET API and once the response is received we are calling processSuccessResponse method as a callback. It seems correct, but suppose we want to call the second API once we get the first API response, similarly the third API when we get the first API response. Let’s see it as an example, we will be calling the same API for now:

function getAPIRequest(_callbackOnSuccess_, _callbackOnError_){    
  var getReq1 = new XMLHttpRequest();  
  getReq1.open("GET", "https://reqres.in/api/users?page=2");  
  getReq1.send();  
  getReq1.onload = () => {  
    alert("The response is " + request.response);  
    var getReq2 = new XMLHttpRequest();  
    getReq2.open("GET", "https://reqres.in/api/users?page=2");  
    getReq2.send();  
    getReq2.onload = () => {  
      alert("The response is " + request.response);  
      var getReq3 = new XMLHttpRequest();  
      getReq3.open("GET", "https://reqres.in/api/users?page=2");  
      getReq3.send();  
      getReq3.onload = () => {  
        alert("The response is " + request.response);  
        //another api call or some other processing  
      }  
    }  
  }  
}
getAPIRequest();

As we can see this thing can grow very large and it will become difficult to read, maintain the code, and understand if any issues come later on.

The promise is the answer to the above problem, it has consumer code that is kind of callback, and all consumers can be written separately and they will be executed one after another.

How To Write Promise Producer Code

Promise producer code is the part that produces some result or output, which later can be processed by a consumer. Let’s try to call a GET API which is like our producer code and its result will the response which we are getting from the API.

function getFirstAPIRequest() {  
  return new Promise(function(resolve, reject) {  
    var getReq = new XMLHttpRequest();  
    getReq.open("GET", "[https://reqres.in/api/users?page=2](https://reqres.in/api/users?page=2)");  
    getReq.send();  
    getReq.onload = () => {  
      if(getReq.status == 200){  
        resolve(getReq.response);  
      }else{  
        reject(new Error("There was some problem in the request."));  
      }  
    }  
  });  
}

Note: Open https://playcode.io/ and paste this code. If you want to learn do practice with this code.

The function passed to Promise is called executor, it runs automatically when the promise is created. The resolve and reject are callbacks provided by JavaScript itself.

When the executor gets the result we can call these callbacks depending on our requirement. Like in our case we called resolve in case of response status is 200 else we are calling reject.

Promise Object Properties

The Promise object created using the new keyboard has two properties state and result.

They change their values as follows

  • state will be pending at first, if resolve is called it will change to resolved state else if reject is called it will change to rejected state.
  • result will be undefined at first, response when resolve(response) is called else error when reject(error) is called.

How To Write Promise Consumer Code

If we want to consume response, we can do that in three ways in Promise using then, catch, and finally.

  • then Consumer Code

The then method of Promise accepts two function arguments, the first one is executed when resolve is called and the second one is executed when reject is called.

function getFirstAPIRequest() {  
  return new Promise(function(resolve, reject) {  
    var getReq = new XMLHttpRequest();  
    getReq.open("GET", "[https://reqres.in/api/users?page=2](https://reqres.in/api/users?page=2)");  
    getReq.send();  
    getReq.onload = () => {  
      if(getReq.status == 200){  
        resolve(getReq.response);  
      }else{  
        reject(new Error("There was some problem in the request."));  
      }  
    }  
  });  
}
getFirstAPIRequest()  
  .then((response) => console.log(response), (error) => console.log  
("Cannot process response"));

This will produce the following output.

If we only want to consume resolve callback we can remove second method definition:

getFirstAPIRequest()  
  .then((response) => console.log(response));

_If we only want to consume reject callback we can pass null as the first argument and second any function definition._

getFirstAPIRequest().then(null, (error) => console.log("Cannot process response"));
  • catch Consumer Code

For handling reject callback promise has one special method called catch. We can write our definition inside it, which will be called only in case when reject callback is called.

getFirstAPIRequest().catch((errorMsg) => console.log(errorMsg));
  • finally Consumer Code

There may be some cases where we want to close some resources before completing the callback. Then we use finally, it has only function definition (without any arguments) which will always be called. Once completed the execution will be passed to next function.

getFirstAPIRequest()  
  .finally(() => console.log("Closing important resources))  
  .then((response) => console.log(response), (error) => console.log  
("Cannot process response"));

Now suppose callback chaining case where we want to call another API on based on the response from the first API. Let’s see an example:

function getFirstAPIRequest() {  
  console.log("Processing first call");  
  return new Promise(function(resolve, reject) {  
    var getReq = new XMLHttpRequest();  
    getReq.open("GET", "[https://reqres.in/api/users?page=2](https://reqres.in/api/users?page=2)");  
    getReq.send();  
    getReq.onload = () => {  
      resolve(getReq.response);  
    }  
  });  
}
function getSecondAPIRequest(firstResponse) {  
  //do some processing on response, here I am passing the first simply  
  console.log("Processing second call");  
  return new Promise(function(resolve, reject) {  
    var getReq = new XMLHttpRequest();  
    getReq.open("GET", "[https://reqres.in/api/users?page=2](https://reqres.in/api/users?page=2)");  
    getReq.send();  
    getReq.onload = () => {  
      resolve(getReq.response);  
    }  
  });  
}
getFirstAPIRequest()  
  .then((response) => getSecondAPIRequest(response))  
  .then((response) => console.log(response));

This will produce the following output.

I hope all the above examples will make you understand what Promise is in JavaScript, how it is better then Callback as it gracefully handles Callback Hell.

Follow me over Medium for such articles @CodeSprintPro

Top comments (0)