Callback functions are probably the most commonly used functional programming technique in JavaScript . Moreover, you can find them in just about every piece of JavaScript code. Yet, they remain mysterious to many JavaScript developers. We will solve this mystery by the end of this article. We will be covering the following details to understand the concept of callbacks in JavaScript:
- What is a callback function?
- Why and When to use a callback function in Javascript?
- How to use callbacks in JavaScript?
- Procedure to use named functions as callbacks
- Procedure to use anonymous functions as callbacks
- How to invoke a callback inside another callback?
What is a callback function?
A callback, as the name suggests, is a function that is to execute after another function has finished executing. As we know, in JavaScript, functions are objects. Because of this, functions can take functions as arguments, and other functions can also return it. Functions that take the additional function as a parameter are called higher-order functions, and the function which passes as an argument is called a callback function
Let's represent it with the help of the following image:
.
As we can see from the above image, the high order function takes the callback function as a parameter. Additionally, the callback function will invoke as the last statement of the high order statement. Which, in turn, will ensure that the callback will always invoke after the high order function has completed its execution.
Why and When to use callback functions in Javascript?
We know that in JavaScript, most of the functions are asynchronous, i.e., whenever a user instantiates a function, JavaScript will not wait for its response and will continue its execution of next statements without waiting for the function to complete its execution.
Let's try to understand this situation detail with the help of following code snippet:
<html>
<body> Demonstrating function callflow without async in javascript:</br>
<script type="text/javascript">
function first(){
console.log("Inside function: first");
}
function second(){
console.log("Inside function: Second");
}
first();
second();
</script>
</body>
</html>
Save the file with name functionCallFlowWithoutAsync.html and open it in any browser (Chrome, Firefox, or IE). It should show the output as:
As we can see in the above screenshot, the output printed on the browser console depicts that the invoking of the functions happens in the mentioned order, i.e., the first() function is invoked and prints its output. Then the second() function invokes and prints its output.
But now let's consider a case, where the function "first()" is unable to return the value within the stipulated time. e.g., Consider a situation where it is doing some I/O operation or invoking an API, which is taking more time to return the response. Javascript will continue its execution of the next statements and will not wait for that task to complete its execution.
We can simulate such behavior by modifying the above-written program as follows:
<html>
<body> Demonstrating function calll with async in javascript:</br>
<script type="text/javascript">
function first(){
// Simulate a code delay
setTimeout( function(){
console.log("Inside function: first");
}, 1500 );
}
function second(){
console.log("Inside function: second");
}
first();
second();
</script>
</body>
</html>
Save the file with name functionCallFlowWithAsync.html and open it in any browser (Chrome, Firefox, or IE). It should show the output as:
Here, we explicitly introduced a time delay of 1500 ms before returning the response from the function first(), and the screenshot depicts that JavaScript didn't wait for the first() function to finish its execution, and it continued with the execution of second() function. Consequently, the response shows that the output of the second() function prints before the output of the first() function.
So, It's not that JavaScript didn't execute our functions in the order we wanted it to, but it's instead JavaScript didn't wait for a response from first() before moving on to execute second().
So, how do we ensure that the flow and order of execution are as per the developer's expectations? The answer to this is Callbacks. Which, in turn, ensures that specific code doesn't execute until another code has already finished the execution. Let's move to the next section, where we will see how to implement callbacks to ensure the needed order of execution for a program.
How to use callback functions in JavaScript?
As discussed above, the callback is a function that passes as a parameter to the other function. In this section, we will cover the details of how callback can be defined and used. We will be covering the details for the following types of functions:
- How to use named functions as callbacks?
- How to use anonymous functions as callbacks n JavaScript?
- Procedure to invoke one callback inside another callback?
How to use named functions as a callback function?
When the callback function uses a named function, it follows the following syntax:
Syntax:
// Suppose there is function function1(), which should be invoked
// before function2(), then function1() can take a callback as parameter
// which will be invoked as last statement of the function1().
function function1(var1, var2, ....., varN, callback)
{
//Statements to get executed
callback(var1,var2,var3……,varN);
}
function2(var1, var2,.....,varN)
{
//Statements to get executed;
}
// While invoking function1(), pass function2() as parameter
function1(var1,var2,......,varN,function2);
To understand it in more detail, let's modify the above example, to pass the second() method as a callback to the first() function.
<html>
<body> Demonstrating callback in javascript:</br>
<script type="text/javascript">
function first(callback){
// Simulate a code delay
setTimeout( function(){
console.log("Inside function: first");
callback();
}, 1500 );
}
function second(){
const outPutElem = document.createElement("div");
console.log("Inside function: second");
}
first(second); // Invoke only first() function, it will auto-invoke second()
</script>
</body>
</html>
Save the file with name callback.html and open it in any browser (Chrome, Firefox, or IE). It should show the output as:
In the above example, we have passed the second() function as a callback function to first() function, and it ensures that the second() function invokes after all the processing of the first function has completed its execution only.
Let's see one more example to explore the callback functionality a bit more. Suppose the user wants to pass different functions as the callback parameter, then the same is also feasible. It will just need the parameter to be changed while invoking the function.
Consider the below code snippet:
<html>
<body>
Demonstrating callback function in javascript. </br>
<script type="text/javascript">
function multiply(a, b, callback)
{
var result = a * b;
callback(result);
}
function ouput(sum)
{
console.log("I am in output function");
console.log("Multiplication of the provided inputs are: " + sum);
}
function display(sum)
{
console.log("I am in display function");
console.log("Multiplication of the provided inputs are: " + sum);
}
multiply(5, 6, ouput); // output is passed as callback
multiply(7, 6, display); // display is passed as callback
</script>
</body>
</html>
Save the file with name callback2Function.html and open it in any browser (Chrome, Firefox, or IE). It should show the output as:
In the above example, we can see that when the multiply() function invokes, the first-time callback parameter is output() function, and when it invokes for the second time, the callback function is display(). In this way, the callback can be used to invoke different functions based on the programmer's needs.
Procedure to use anonymous functions as callbacks in JavaScript
JavaScript allows passing the function definition as the callback parameter directly.
Let's validate the same using below code snippet:
<html>
<body> Demonstrating anonymous as callback in javascript:</br>
<script type="text/javascript">
function first(callback)
{
// Simulate a code delay
setTimeout( function()
{
console.log("Inside function: first");
callback();
}, 1500 );
}
first(function () // Anonymous function passed as callback
{
console.log("Inside function: second");
});
</script>
</body>
</html>
Save the file with name callbackAnonymous.html and open it in any browser (Chrome, Firefox, or IE). It should show the output as:
In the above example, we have directly passed the function definition while invoking the function first(), and the same gets invoked as the callback function.
How to invoke a callback function inside another callback?
Now to take it one step further, apart from using the callback functions inside the functions, we can have callback function inside another callback function. While calling the first callback function, we need to pass what should be other callback function values. Its syntax looks like below:
Syntax:
function1(var1,var2,.....,varN,callback){
callback(var1,var2,var3….,varN);
}
callBack1(var1,var2,.....,varN,callback){
callback(var1,var2,var3….,varN);
}
callBack2(var1,var2,.....,varN){
//statements need to get executed
}
funtion1(var1,var2….varN,callBack1(callBack2)); // Here one callback is passed as parameter to another callback
Let's try to understand it in detail with the help of the following example:
<html>
<body>
Demonstrating callback function in javascript. </br>
<script type="text/javascript">
// The multiplee function accepts two parameteers
function multiply(a, b, callback1, callback2)
{
var result = a * b;
callback1(result, callback2); //callback2 is passed as parameter to callback1
}
function ouput(result)
{
console.log("I am in output function");
console.log("Multiplication of the provided inputs are: " + result);
}
function display(result, callback)
{
console.log("I am in display function");
console.log("Multiplication of the provided inputs are: " + result);
callback(result);
}
function CallBackFunction(result) {
console.log("I am inside callback function");
}
multiply(5, 6, ouput); // output is passed as callback
// display and CallBackFunction are passed as callbacks
multiply(7, 6, display, CallBackFunction); // display is passed as callback
</script>
</body>
</html>s
Save the file with name callback3Function.html and open it in any browser (Chrome, Firefox, or IE). It should show the output as
Here, we use the display() as a callback function, which in-turn also expects a callback function as a parameter. So this way, we can chain multiple callback functions to ensure the order of execution for various functions is maintained. We can see from the console output that first, the output() function was invoked, followed by the display() and CallbackFunction().
What is callback hell?
When you have lots of callback functions in your code! It gets harder to work with them. The more of them you have in your code, and it gets particularly bad to invoke and handle them. It occurs because, in JavaScript, the only way to delay computation so that it runs after the asynchronous call returns is to put the delayed code inside a callback function. You cannot delay code that we wrote in a traditional synchronous style, so you end up with nested callbacks everywhere. Consider the following example to understand the problem in more detail:
<html>
<body> Demonstrating callback in javascript:</br>
<script type="text/javascript">
function i_take_10_sec(callback) {
return setTimeout(() => {
document.write('I was no: 1 and I take 10 seconds</br>')
callback()
}, 10000);
}
function i_take_1_sec(callback) {
return setTimeout(() => {
document.write('I was no: 2 and I take 1 second</br>')
callback()
}, 1000);
}
function i_take_5_sec(callback) {
return setTimeout(() => {
document.write('I was no: 3 and I take 5 second</br>')
callback()
}, 5000);
}
function i_take_7_sec(callback) {
return setTimeout(() => {
document.write('I was no: 4 and I take 7 second</br>')
callback()
}, 7000);
}
function run (){
i_take_10_sec(()=>{
i_take_1_sec(()=>{
i_take_5_sec(()=>{
i_take_7_sec(()=>{ })
})
})
})
}
run();
</script>
</body>
</html>
Save the file with name callbackMulti.html and open it in any browser (Chrome, Firefox, or IE). It should show the output as:
Looking at the code above, don't you see that the nested invocation of functions from line 42 to 47, has made the code very difficult to read and understand. This problem is known as a callback hell or the pyramid of doom. We will cover the details in the following chapters to understand what solutions JavaScript has provided for handling this problem of callback hell.
Key Takeaways:
- When you want one function to execute only after another function has completed its execution, we use callback functions in JavaScript.
- It needs to pass as a parameter to other functions to make a function callback. The function which accepts the callback as a parameter is known as "High order function".
- Callback functions can be both a "named function" or an "anonymous function".
- Callback hell happens when you have multiple callback functions, chained with each other.
Let's move to the next article under the concept of "Strings in JavaScript".