Most of us feel confusion while learning about asynchronous behavior of JavaScript. In this article i tried to explain need and nature of callbacks with simple examples.
JavaScript is a single threaded language. This means it has one call stack and one memory heap. As expected, it executes code in order and must finish executing a piece code before moving onto the next.
Let us understand the above statement with a very simple example. Let us take a use case as " Find big number in given two numbers and then add 10 to that big number". It is very simple example which can help us to understand asynchronous behavior of JavaScript.
The above use case has two tasks. One is finding big number and second one is adding 10 to the result of first task.
Let me take two functions to implement above two tasks.
var bigNumber;
//function to find big number
function findBig(firstNumber,secondNumber)
{
if(firstNumber>secondNumber){
bigNumber=firstNumber;
}
else if(firstNumber==secondNumber){
bigNumber=firstNumber;
}
else{
bigNumber=secondNumber;
}
}
//function to add 10 to big number
function incrementResultBy10(){
let result=bigNumber+10;
console.log("big number is ",bigNumber);
console.log("result after increment is ",result);
}
//call functions
findBig(100,200);
incrementResultBy10();
we will get output as
big number is 100
result after increment is 110
Everything is as we expected and nothing to confuse. Great....
Now, let us assume as it may take some time to find and to return big number. It is not really happened here. All I/O operations are blocking operations.But to understand callbacks with simple example,let us make this assumption. For this we can use
setTimeout(()=>{},timeout)
var bigNumber;
//function to find big number
function findBig(firstNumber,secondNumber)
{
if(firstNumber>secondNumber){
setTimeout(() => {
bigNumber=firstNumber;
}, 1000);
}
else if(firstNumber==secondNumber){
setTimeout(() => {
bigNumber=firstNumber;
}, 1000);
}
else{
setTimeout(() => {
bigNumber=secondNumber;
}, 1000);
}
}
//function to add 10 to big number
function incrementResultBy10(){
let result=bigNumber+10;
console.log("big number is ",bigNumber)
console.log("result after increment is ",result);
}
//call functions
findBig(200,200);
incrementResultBy10();
Now, surprisingly we got output as
big number is undefined
result after increment is NaN
Why??????
What is happening behind ?????
Let us focus on understanding this behavior. As we knew JavaScript is single threaded, with one call stack, it will take support of WebAPI to execute things asynchronously. That means, In this example, the function call( findBig(200,200)) will start execution. Inside of it,setTimeout() method is existed. Then JavaScript will forward that to WebAPI and meanwhile, It will execute the second function call(incrementResultBy10()). Then this function will execute before the first function completes its timeout. That's why we got such result where variable bigNumber is not assigned with actual value until the first function completes its execution.
Let us fix this issue
The solution to this problem is , the second function (incrementResultBy10()) should wait until the first function call(findBig(200,200)) is completed. But how to control flow of execution as per our need. Callbacks are introduced to solve these kind of problems.
Callback function
Callback function is an argument to another function,which will be executed eventually ,when outside function completes its execution.
This can help us to fix the above issue. Now let us refine the findBig(firstNumber,secondNumber) using callback function like below.
function findBig ( firstNumber , secondNumber , callback)
{
if(firstNumber>secondNumber){
setTimeout(() => {
callback(firstNumber);
}, 2000);
}
else if(firstNumber==secondNumber){
setTimeout(() => {
callback(firstNumber);
}, 2000);
}
else{
setTimeout(() => {
callback(secondNumber);
}, 2000);
}
}
Now the third parameter is "callback" which can receive a function as argument and execute after timeout.Now let us efine second task which can add 10 to big number like below.
function incrementResultBy10(bigNumber){
let result=bigNumber+10;
console.log("big number is ",bigNumber)
console.log("result after increment is ",result)
}
Then pass this function as third argument to findBig() function.
findBig(200,1000,incrementResultBy10)
Now , the second function can be executed only after the completion of findBig() function.Hence the issue is resolved.
Hope you understand the need and behavior of callbacks in JavaScript. With this understanding, we can use callbacks to deal with blocking I/O operations.
Top comments (0)