What the heck is callback?

Any function that gets passed to another function as an argument and gets called by that function is Callback function. It is just a regular function that is passed into another function. Functions are first class object therefore they can be passed as arguments into functions.

function hello(x){
  console.log('Hello ' + x);
}

function greet(name, callback){
  callback(name);
}

greet('Peter',hello);
// Hello Peter

Here hello function is callback function because it is passed to greet function. It gets called inside greet function.

greet function is high order function because it accepts function (hello function) as a parameter.

In our example, parameter for callback function is named callback but it can be name anything.

We used declared function as a callback function in our example above. We can also use anonymous function as callback function. Some referred it as inline callback.

function greet(name,cb){
  cb(name);
}

greet('Peter',function(name){
console.log('Hello ' + name)
})
// Hello Peter

What are callback used for?

Callbacks helps to keep code DRY

Browser Events

const button = document.querySelector('button')

function onClick(e) {
  console.log('clicked')
}

button.addEventListener('click', onClick);
// clicked

Here is a simple example of browser event with callback. In this example, const button is set to listen for click event and when click event happens onClick function is called.

Here, addEventListener is high order function and onClick is callback function.

Declarative Readable Code

Callback function helps us write code in a declarative style.

In declarative style we declare the intent of our code so that reader can easily understands what we are trying to accomplish with the it. Readers are only concern with the outcome of the code.This makes code more readable and communicative.

Let’s illustrate it with an array method.

const arr1 = [3, 8, 5, 7, 9, 12, 4];

const arr2 = arr1.filter(function(num){
  return num > 5
});

console.log(arr2);
// [ 8, 7, 9, 12 ]

Here array method filter accepts anonymous function as callback that filters numbers greater than 5 from arr1 array and assign it to arr2 array.

Now let’s rewrite our code without the use of callback function in a imperative style.

const arr1 = [3, 8, 5, 7, 9, 12, 4];

const arr2 = [];

for(let i = 0; i< arr1.length;  i++){
  if( arr1[i] > 5 ){
  arr2.push( arr1[i] )
 }
}
console.log(arr2);
// [ 8, 7, 9, 12 ]

There are so many things happening here. We are iterating arr1 array with for loop. We are checking each index of arr1 to be greater than 5 and pushing it to arr2.

Compare to imperative style, declarative way is much more clean and concise. We are not declaring any variables. We are not instructing javascript to how to and how many times to loop through array. We are only filtering numbers greater than 5 from arr1 and pushing it to arr2.

Asynchronous javascript

Consider you are writing a code that fetches data from server and displays that data. In real working environment when we make request to server, we don’t know how long it will take to complete the request. Here we will use setTimeout function to mimic fetching data from server.

function fetchData(){
  setTimeout(function(){
    console.log("Fetch Data")
  }, 2000);
}

function displayData(){
  console.log("Display Data");
}

fetchData();

displayData();

// Display Data
// Fetch Data

In our example when we invoke fetchData it takes about 2000 milliseconds to console log ‘Fetch Data’. Since we are mimicking fetching data from server consider it to be amount of time it took get data from server.

After invoking fetchData, we invoked displayData that console logged ‘Display Data’ almost immediately.( Assume that displayData function is displaying data we got from server)

So in our code example, we console logged Display Data before Fetch Data even though we invoked fetchData first. This is the example of Asynchronous javascript. While waiting for response from fetchData function, javascript moved to the next line of code and executed displayData function.

But this is not what we want. If this was real program this would have certainly caused error. So how do we fix this? How do we console log in right order? Answer is with Callback function.

Let’s rewrite the above code with callback function.

function fetchData(cb){
  setTimeout(function(){
    console.log("Fetch Data");
    cb()
   },2000);
}

function displayData(){
  console.log("Display Data");
}

fetchData(displayData);

// Fetch Data
// Display Data

Now we have fetchData function that accepts callback. So when we invoke fetchData we pass in displayData function.

displayData function gets called only after we have console logged ‘Fetch Data’. Hence allowing us to console log in the order that we want.

In real case scenario with callback function we make sure that we display data only after data is returned from the server.