DEV Community

Sachin Sarawgi
Sachin Sarawgi

Posted on

Callback Deep Dive in JavaScript

In this blog, we will understand how callback function works in JavaScript and how to write one.

Topic Covered

  • What is a Callback Function?
  • Which Use Case Solved by Callback Function
  • Callback Function Synchronous Execution
  • Callback Function Asynchronous Execution
  • Nesting Callback Function Asynchronous Execution

What is a Callback Function

In JavaScript, functions are first-class objects. Just like we can pass objects to functions, we can pass functions as an argument to another function.

Now the functions which are passed an argument will execute later, after the function where it is passed already executed. That function is commonly known as Callback Function. Generally, this type of function waits for some event to happen or some timeout then it will get executed.

Functions that accept another function as an argument is called a higher-order function.

An understanding of callback is very much necessary. As event and callback structure is the mechanism by which JavaScript engine is managing multiple overlapped requests for I/O.

JavaScript is a synchronous language by nature. The event and callback functions 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.

Which Use Case Solved by Callback Function

  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. Now, we don’t want the user to wait till then, that will be a bad design. Here comes the Callback as a savior.
  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. This may not work as the script can be not loaded yet.

Example solution for 1st case using a callback: We can write the response processing code inside a function, pass that function as an argument to a function that is calling the API. The response processing function will wait till it gets the response to process while the main function will complete its execution and exit. Similarly, we can do something about the second use case.

Callback Function Synchronous Execution

Let’s first start with a simple example of a callback function.

function welcome(greetingMsg, callback){  
  console.log("Before calling callback");  
  callback(greetingMsg);  
  console.log("After calling callback");  
}
function sayMyName(greet){  
  console.log(greet + " Professor");  
}
welcome("Hello", sayMyName);

This is one of the simplest examples where the callback function which we passed as an argument will be executed synchronously.

This may not be an important use case of using Callback Function so let’s jump into asynchronous calling.

Callback Function Asynchronous Execution

Let’s take our first use case where we need to wait for the response to the process. We can solve it by callback function async execution.

Here we will be using XMLHttpRequest object to request an API. XMLHttpRequest object is provided by the browser, it’s built-in browser object. I have used a sample API which will give a JSON response for testing purposes.

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

Open https://playcode.io/ and paste this code. You will see it gives a pop up that has the API response.

XMLHttpRequest onload is an event that will occur when we get a result from the API. We can register our function for processing the response in the onload event. We are checking if the response code is 200 pass the request object to the callback function which is processSucessResponse. Let’s see how we can process an error response if the status code is 400.

function getAPIRequest(_callbackOnSuccess_, _callbackOnError_){

  var getReq = new XMLHttpRequest();  
  getReq.open("GET", "https://reqres.in/api/users?page=2");  
  getReq.send();  
  getReq.onload = () => {  
    if(getReq.status == 200){  
      callbackOnSuccess(getReq);  
    }else if(getReq.status == 400){  
      callbackOnError();  
    }  
  }  
}
function processSucessResponse(_request_){  
  alert("The response is " + request.response);  
}
function processErrorResponse(){  
  alert("The response has some errors.");  
}
getAPIRequest(processSucessResponse, processErrorResponse);

If you know ajax it can be easy as follows:

function getAPIRequest(_callbackOnSuccess){_  
  ajax("https://reqres.in/api/users?page=2", _callbackOnSuccess_);  
}
function processSucessResponse(_request_){  
  alert("The response is " + request.response);  
}
getAPIRequest(processSucessResponse);

Note: All the asynchronous functionality in JavaScript is provided by some external framework or library. Whenever JavaScript engine sees an external API call, it will ask the browser this is yours to execute, and whenever you get a response run this code (the callback function code).

The browser then waits for the response to return, whenever it has some response it will schedule the callback function execution by putting it into the event loop.

Nesting Callback Function Asynchronous Execution

It may happen after getting a response from the first API we may want to fire another request based on the result. This kind of request is like a nested API request. For simplicity, we will be calling the same API.

function getAPIRequest(_callbackOnSuccess_, _callbackOnError_){  
  var getReq = new XMLHttpRequest();  
  getReq.open("GET", "https://reqres.in/api/users?page=2");  
  getReq.send();  
  getReq.onload = () => {  
    if(getReq.status == 200){  
      callbackOnSuccess(getReq, processNestedResponse);  
    }else if(getReq.status == 400){  
      callbackOnError();  
    }  
  }  
}

function processSucessResponse(_request_, _callbackOnSuccess_){  
  alert("The response is " + request.response);  
  var getReq = new XMLHttpRequest();  
  getReq.open("GET", "https://reqres.in/api/users?page=2");  
  getReq.send();  
  getReq.onload = () => {  
    if(getReq.status == 200){  
      callbackOnSuccess(getReq);  
    }  
  }  
}
function processErrorResponse(){  
  alert("The response has some errors.");  
}
function processNestedResponse(_request_){  
  alert("The response is " + request.response);  
}
getAPIRequest(processSucessResponse, processErrorResponse);

This example explains how we can handle the nested API request.

I hope this blog gave you a better understanding of what is a callback, when we can use callback and how to write it in JavaScript code.

Follow me over Medium for such articles @CodeSprintPro

Top comments (0)