Callbacks in Javascript

Debarati Ghatak
Last Updated: May 13, 2022

Introduction

Callback, in simple terms means,

‘I'll call back once I'm done!’

Yes, you got that right! In JavaScript, we use Callbacks if we want to invoke/call a function after executing another function. 

 

Source: Giphy

What are Callbacks in JavaScript?


In JavaScript, Functions are known as ‘first-class objects’/ ‘first-class citizens’. It is because functions can have properties and methods just like objects.

Objects can be passed as a parameter to functions. Similarly, a function can also be passed as a parameter to another function. Here, the function passed as a parameter to the other function is known as ‘Callback’.

Let us understand Callbacks with the help of a simple example,

Code:

// message function
function message(colour) {
    console.log(`My favourite colour is ${colour}`);
}
// favouriteColour function with 'callbackFunction' as argument
function favouriteColour(callbackFunction) {
    let colour = 'pink';
    callbackFunction(colour);
}
// Calling 'favouriteColour' function and passing 'message' function as argument
favouriteColour(message);

 

Output:

My favourite colour is pink 

 

In the above code, we have two functions - message and favourite Colour. But we are only invoking the function favouriteColour in the last line of our code.

So how is the message function getting called/invoked?

The message function is used as a callback in the above code. It is passed as an argument of favouriteColour function. After favouriteColour is done with its work (here, work refers to initializing variable ‘colour’ as ‘pink’), it calls the message function. The message function then prints the output message.

 

The basic structure of a callback function is, 

function some_function(callback_function) {  

    callback_function();

}

some_function(callback_function);

 

NOTE: 

This is correct,

FavouriteColour(Message);

 

But this is incorrect,

FavouriteColour(Message());

 

You do not have to use curly brackets to pass the callback as an argument.

Definition

‘A function that is passed an argument to another function is called a Callback function.’

  • A callback function can be called from another function.
  • It starts executing after another function has finished executing. Hence the name ‘callback’. 

Anonymous function as Callback

We can use Anonymous functions as Callbacks.

Code:

// favouriteColour function with 'callbackFunction' as argument
function favouriteColour(callbackFunction) {
    let colour = 'pink';
    callbackFunction(colour);
}
// using anonymous function for callback
favouriteColour(function message(colour) {
    console.log(`My favourite colour is ${colour}`);
});

 

Output: 

My favourite colour is pink

Why do we need Callbacks?

  • JavaScript is an event-driven programming language. Instead of waiting for a response before moving on, JavaScript will keep executing while listening for other events.
  • Using Callbacks, we can ensure certain code does not get executed until the other code has already finished execution. So we can achieve better control over functions in JavaScript using Callbacks.
  • Callbacks shine the most in the case of asynchronous operations. Examples of such asynchronous operation can be 
    • reading/writing data in a file
    • making an API request

Synchronous and Asynchronous Callbacks

Callbacks in JavaScript are of two types - Synchronous and Asynchronous. Let us look at them, one by one.

Synchronous Callback

Synchronous code is always executed in sequence - one statement after the other. In the case of Synchronous Callback, the callback is executed when the calling function calls it. Synchronous callbacks are blocking. 

Code:

function function2() {
    console.log('Within the Callback function - This gets executed next!');
}

function function1(callbackFunction) {
    console.log('Within function1 - This gets executed first! Calling callback function ... ');
    callbackFunction();
    console.log('Within function1 - Callback has finished executing! ')
}
// function1 method called, with function2 method as a callback
function1(function2);

 

Output:

Within function1 - This gets executed first!Calling callback function ...
Within the Callback function - This gets executed next!
Within function1 - Callback has finished executing!

 

In the above code, function1 gets executed first. After function1 has been executed, the callback function2 gets executed.


Asynchronous Callback

In the case of Asynchronous Callback, the callback is executed later, after the calling function calls it. Asynchronous callbacks are non-blocking. 


Code:

function function2() {
    console.log('Within the Callback function - This gets executed next!');
}

function function1(callbackFunction) {
    console.log('Within function1 - This gets executed first! Calling callback function ... ');
    setTimeout(callbackFunction,3000);
    console.log('Within function1 - Callback has finished executing! ')
}
// function1 method called, with function2 method as a callback
function1(function2);

 

Output:

Within function1 - This gets executed first! Calling callback function ...
Within function1 - Callback has finished executing!
Within the Callback function - This gets executed next!

 

We have used the setTimeout() function to make an asynchronous callback in this code.

You can observe that the output is not similar to the previous code’s output. Here the Callback function does not get executed before 3 seconds have passed.

Handling Errors using callbacks

Two callbacks can be introduced in the code to handle errors - one for success and one for failure.

Code:

const code = 999;
function compare(input, success, failure) {
    if (input == code) {
        success();
    } else {
        failure();
    }
}
function onSuccess() {
    console.log('Success! The code is correct');
}
function onFailure() {
    console.log('Failure! The code is incorrect');
}
compare(999, onSuccess, onFailure);
compare(5464, onSuccess, onFailure);

 

Output:

Success! The code is correct
Failure! The code is incorrect

 

If the variable code matches with the input data in the above code, the success callback is invoked. But if the code does not match with input data, the failure callback is called to handle the failure.

Callback Hell/ Pyramid of doom

‘Pyramid of Doom’ arises when multiple levels of nested indentation control access to a function. The ‘pyramid’ keeps expanding to the right with every step. It is also known as the ‘Callback Hell’. 

Source: Medium

The Callback Hell structure essentially has one function, inside another function, which is also inside another function and so on. The code becomes challenging to understand and maintain with multiple nested calls.

Code:

loadScript('1.js', function(error, script) {

    if (error) {
      handleError(error);
    } else {
      // ...
      loadScript('2.js', function(error, script) {
        if (error) {
          handleError(error);
        } else {
          // ...
          loadScript('3.js', function(error, script) {
            if (error) {
              handleError(error);
            } else {
              // ...continue after all scripts are loaded (*)
            }
          });
 
        }
      });
    }
  });

Source: javascript.info

The code above illustrates a ‘Callback Hell’. 

How to avoid Callback Hell?

With Callback Hell, the code becomes completely unreadable, making the code very hard to understand. However, there are a few ways to avoid callback hell:

  • By using promises
  • By using async/await functions
  • Dividing a bigger function into smaller functions

Frequently Asked Questions

Q1 What is setTimeout in JavaScript?

Ans: The setTimeout is an asynchronous function that calls a function after a certain interval. 

Syntax:

setTimeout(function,time);

Function - It refers to the function to be executed after a certain interval of time.

Time - It refers to the interval of time. The unit is milliseconds.

Example:

Code:

function func() {
    console.log('I am printed after 5 seconds!');
}
setTimeout(func, 5000);
console.log('I am printed first!');

 

Output:

I am printed first!
I am printed after 5 seconds!

 

Here the statement inside the function func() is printed exactly after five seconds( 5000 milliseconds).

 

Q2 Can we pass functions as an argument to another function in JavaScript?

Ans: Yes, we can pass functions as an argument to another function in JavaScript. Such functions that are passed as arguments are known as Callbacks.
 

Q3 What is closure in JavaScript?

Ans:

According to Mozilla,

A closure is a combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).

In simpler terms, closures are functions that can access variables outside their function body.

Example:

Code:

let a = 5;
function add(b)
{
    let sum = a +b;
    console.log(`The sum is ${sum}`);
}
add(10);

 

Output:

The sum is 15

 

Here the function ‘add’ accesses variable ‘a’ outside the function. It then displays the summation of values a and b.
 

Q4 Is JavaScript an event-driven programming language?

Ans: Yes, JavaScript is an event-driven programming language. Instead of waiting for a response before moving on, JavaScript will keep executing while listening for other events.

Key Takeaways


In this blog, we discussed Callbacks in-depth. We saw why it is essential and the different types of Callbacks, handling errors with Callbacks and Callback Hell. We hope you learned something new in this blog. 

If you are new to Web Development, we suggest you get your fundamentals crystal clear with our Full Stack Development course

Happy Learning Ninja!

Was this article helpful ?
0 upvotes

Comments

No comments yet

Be the first to share what you think