What is a Callback Function in Javascript?
A callback function in javascript is a function that is passed as an argument in another function. Which is then called inside the parent function to complete a routine or an action. To put it more simply, it is a function that will be called(executed) later after its parent function(the function in which it is passed as an argument) is done executing.
Let's see an example :
Output :
In the above code, we can see in the function operation the third parameter is a callback function. We are first passing the "callback" as an argument and then calling it inside the parent function , operation. Here, we have taken the "sum" as the callback function, we can create any function and pass it as the callback in the operation function.
Need for Callback Functions
Javascript is a single-threaded language, which means, it executes the code sequentially one line after another. However, there are some cases in which a part of the code will only run after some lines of code, i.e. it is dependent on another function. This is called asynchronous programming.
-
We need callback functions to make sure that a function is only going to get executed after a specific task is completed and not before its completion.
- For instance, in the case of an event listener, we first listen for a specific event, and if the function detects it, then only the callback function is executed. It's just like when you go into a restaurant, the function(action) to make a pizza will only run after you order a pizza. And in the meantime, the restaurant staff(browser or nodeJS) will do some other work.
-
Callback functions are also needed to prevent running into errors because of the non-availability of some data that are needed by some other function.
- For example, when a function fetches some data from an API that takes some time to get downloaded. We use the callback function here so that the function that needs the data will only get executed when all the required data is downloaded.
Examples
Let's see a few examples of callback functions and how it's used in javascript :
1. Synchronous Callback Function
The code executes sequentially - synchronous programming.
Output :
2. setTimeout() - Asynchronous Callback Function
Output :
The execution of this code is different than what we are used to(synchronous).
Let's see it in detail :
Here, as we can see the code is not running sequentially. The console.log("End"); statement get executed before the setTimeout() function. This is called asynchronous programming.
setTimeout() function takes two parameters the first one is a callback function and the second parameter is the time value in milliseconds. The callback function will get executed after the amount of time specified in the second parameter.
The browser or the nodeJS engine will not wait for the setTimeout() function to execute its callback function. In the meantime, it'll move to the next statement and execute that, in our case, that is console.log("End");.
Let's see the execution of the asynchronous program in detail :
- The browser or the nodeJS has a few components that help in executing the javascript and rendering a web page.
- It consists of a call stack, web APIs, event loop, and callback queue.
- The execution of each function happens inside the call stack.
- The web APIs consist of features that make javascript a superpower. It has setTimeout(), setInterval(), DOM, and other functions and APIs that allows javascript to do a whole bunch of useful things.
- In the above code when we use the setTimeout() function the javascript engine uses the web APIs and gives access to the setTimeout() function.
- This function does not go inside the call stack and blocks the execution. The function gets processed in the web APIs section and when the specified time is over the callback function moves to the callback queue.
- So the call stack is free to execute the other code while the web API is getting processed and the callback function waits in the callback queue.
- When the event loop finds the call stack empty and sees that there is a callback function in the callback queue. The event loop moves that callback function in the call stack and it gets executed.
3. Asynchronous Callback Function
When we fetch data from a server we get it after some delay. The browser doesn't stay idle for that time and it moves to execute the next statement in the javascript program. To execute a block of code or provide the fetched data to the next function in the program we use the asynchronous callback function.
Note :
Here we are using the setTimeout() function to imitate the delay in sending the data by the server.
Output :
Here,
- If we will not use a callback function we will not get the userEmail from the loginUserServer.
- It will give undefined in place of userEmail because at the time of calling the loginUserServer the data from the server is not available(as it takes 5seconds) this is called hoisting.
- However, because we are using the callback function in the loginUserServer() function, the callback waits for the parent function to finish, and then only it executes itself.
Nesting Callbacks and Callback Hell
We can nest callback functions as we nest for loops or if-statements. When we have to run a piece of code that is dependent on some other function and that function is also dependent on the result of another function, the nesting of callback functions happens. This way we can run multiple functions that are dependent on some other functions.
See the program below to get more clarity.
In the above example, we can see one callback nested into another callback function.
The above code looks messed up and it will get even messier with the increase in the number of nested callbacks. This situation is called callback hell where the code is messed up due to multiple nested callback functions. This decreases the readability of the code and makes it difficult to edit.
So to avoid this issue we use different techniques like promises, async, and await(syntax coating).
Example :
As you can see the above code does look like hell! There are some ways to prevent callback hell. Let's see them in detail.
a. Using Promises
A Promise is a javascript object that links producing code and consuming code. Producing code is the code that takes some time like getting data from a server. Consuming code is the code that must wait for the result of the producing code.
Refactoring the above code using the promise :
Output :
This looks much cleaner, and easy to read, and edit. This is one of the advantages of using promises in javascript. Use this JavaScript Beautifier to beautify your code.
Let's see javascript promises in a brief :
- A promise has four states :
- Pending
- Settled
- Fulfilled
- Rejected
- Using these different states a promise does efficient error handling.
- When the action related to the promise is neither fulfilled nor rejected, it's in a pending state.
- When the action related to the promise is either fulfilled or rejected, it's in a settled state.
- When the action related to the promise is executed successfully(resolved), it's in the fulfilled state.
- When the action related to the promise fails(not resolved) due to some error, it's in the rejected state.
- Using the .then() method we can do further actions like calling another callback function or catching the error.
b. Using Async and Await
Using javascript promise we can prevent callback hell and can catch the errors and respond to them. However, the way of writing promise code is something we are not used to(it's the asynchronous way). Using async and await we can write the asynchronous javascript promises code synchronously. In the background it's still using the whole javascript promise code, this is just a better syntax, easier to understand, and write.
Output :
- In the above code, we use the syntax coating of the async and await.
- We create a function and use the async keyword to tell the browser that we are going write an asynchronous function.
- After declaring the function async only we can use await.
- We use the await keyword to wait for the callback function to get executed and then only assign value to the local variables.
Conclusion
- The Callback function in javascript is an important concept and it's used everywhere like :
- In setTimeout(), setInterval(), and addEventListener() functions.
- These functions will be very frequently used in your projects from beginner level to even advanced ones.
- Callback functions start nesting when the size and the complexity of the projects increase and this might cause callback hell which will make the code bulkier and difficult to edit.
- To tackle this problem and also provide some extra functionality we use promises, async, and await.
- async and await method is just a better way to write the asynchronous type of code in a familiar synchronous code.