Javascript callback functions are another important concept you must understand. Otherwise, you might face a lot of struggles in becoming a successful Javascript developer. But I am sure that after reading this article thoroughly, you will be able to overcome any obstacles you previously had with callbacks.
Before, I will talk more about the callback function, but first, you need to have some minimal knowledge about functions. I mean, you should know what a function is, how it actually works, what the different types of functions are, etc.
A Quick Recap: Javascript Function
What is a Function?
A function is a logical building block inside which a set of codes are written in order to perform a specific task. Practically, functions allow writing codes in a more organized way that is also easy to debug and maintain. Functions also allow code reuse.
You define a function once and call it when you need to without writing the same code again and again.
The Syntax for Declaring a Function
We talked a little about what a function is. Now, let's see how to declare a function in JavaScript.
- Using the Function Constructor: In this approach, the function is created with the help of the "Function" constructor. Technically, this approach is less efficient than declaring functions with the function expression syntax and the function declaration statement syntax.
- Using Function Expressions: Typically, this approach is the same as a variable assignment. In simple words, the function body is considered an expression, and that expression is assigned to a variable. Functions defined with this syntax can be either named or anonymous.
A function that has no name is known as an anonymous function. An anonymous function is self-invoked, which means it calls itself automatically. This behavior is also known as immediately invoked function expression (IIFE).
- Using a Function Declaration Statement: Actually, this is the old-school method that is commonly used in Javascript. Here, after the keyword function," you have to specify the name of the function. After that, if the function accepts multiple parameters or arguments, you need to mention them too. Although this part is completely optional,
In the body of the function, the function must return a value to the caller. After a return statement is found, the function will stop executing. Inside the function, the parameters will act as local variables.
Also, the variables that are declared inside the function will be local to that function. Local variables can only be accessed within that function, so variables with the same name can easily be used in different functions.
Invoking a Function
The function declared before will be invoked when any one of the following occurs:
When an event occurs, for example, when a user clicks on a button or selects some option from the dropdown list, etc.
When the function is called from the Javascript code.
The function can also be invoked automatically; we already discussed that in an anonymous function expression.
The () operator invokes the function.
What is the Javascript Callback Function?
As per MDN, A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.
I know that after reading this technical definition, you are confused and hardly able to understand what is actually a callback function.
Let me clarify this with simple words: a callback function is a function that will be executed just after another function has finished executing. A callback function is a function that is passed as an argument to another Javascript function. That callback function is executed inside the function it was passed into.
In Javascript, functions are treated as first-class objects. By saying first-class object, we mean that a number, a function, or a variable can be treated the same as any other entity in the language. Being a first-class object, we can pass functions to other functions as variables, and functions can be returned from other functions too.
Functions that can do this are known as higher-order functions. A callback function is actually a pattern. The word "pattern" means some sort of proven methodology to solve a common problem in software development. There, it is better to call the use of the callback function a callback pattern.
Why do we need a Javascript Callback?
The client-side Javascript runs in the browser, and the main browser process is a single-threaded event loop. If we try to execute long-running operations within a single-threaded event loop, the process is blocked. This is technically bad because the process stops processing other events while waiting for your operation to complete.
For example, the "alert" statement is considered one of the blocking codes in Javascript in the browser. If you run an alert, you can no longer interact within the browser until you close the alert dialog window. In order to prevent blocking on long-running operations, a callback is used.
Let's dive deep so that you will understand exactly in which scenario a callback is used.
In the above code snippet, the getMessage() function is executed first, and then displayMessage() is executed. Both displayed a message in the browser's console window, and both executed immediately.
But in certain situations, some codes are not executed immediately. For example, if we assume that the getMessage() function performs an API call where we have to send the request to the server and wait for the response, then how will we be able to deal with it?
To handle that kind of scenario, we need to use callback functions in Javascript.
How To Use the Javascript Callback Function
Rather than telling you about the syntax of Javascript callback functions, I think it would be better if we tried to implement the callback function in our previous example. The code snippet is shown below in the following screenshot:
In order to use the callback function, we need to perform some sort of task that will not be able to display results immediately. To emulate this behavior, we are using JavaScript's setTimeout() function. That function will take 2 seconds to display the message "Hi, there" in the console window.
After this message is displayed, the "Displayed message" will be shown in the console window of the browser. So in this scenario, at first we are waiting for the getMessage() function, and after this function is executed successfully, we are executing the displayMessage() function.
How Does Javascript Callback Work?
Let me explain what actually happened behind the scenes in the previous example.
As you can see from the previous example, in the getMessage() function, we are passing two arguments: the first argument is the "msg" variable, which gets displayed in the browser's console window, and the second argument is the "callback" function.
Now, you may wonder why the "callback" function is passed as an argument. It's because to implement a callback function, we must pass a function as an argument to another function.
After the getMessage() function finishes its task, we are calling the "callback()" function. After that, when we are calling the getMessage() function, we pass a reference to the "displayMessage()" function, which is treated as a callback function.
Note carefully that, when the getMessage() function is called, we are only passing the reference to the "displayMessage" function. That's why you will not see the function invoke operator, i.e., "()" beside it.
Is the Javascript Callback Asynchronous?
JavaScript is considered a single-threaded scripting language. The term "single-threaded" means that Javascript executes one code block at a time. When JavaScript is busy executing one block, it is not possible for it to move on to the next block.
In other words, we can say that Javascript code is always blocking in nature. But this blocking nature prevents us from writing code in certain situations when we are not able to get immediate results after running some specific tasks.
I am talking about tasks such as the following:
sending an API call to a certain endpoint to get data.
sending a network request to get some resource (for example, a text file, an image file, a binary file, etc.) from a remote server.
To handle these situations, we must write asynchronous codes, and the callback function is one approach to dealing with these situations. So, callback functions are asynchronous in nature.
What is Javascript Callback Hell?
Callback hell occurs when multiple asynchronous functions are executed one after another. It is also known as the Pyramid of Doom.
Let's assume you want to get the list of all GitHub users, and among the users, you want to search for only the top contributors for the Javascript repository. Then, among the people, you want to get details on the person whose name is Jhon.
To implement this functionality with the help of callbacks, the code snippet will be similar as shown below.
http.get('https://api.github.com/users', function(users) {
/* Display all users */
console.log(users);
http.get('https://api.github.com/repos/javascript/contributors?q=contributions&order=desc', function(contributors) {
/* Display all top contributors */
console.log(contributors);
http.get('https://api.github.com/users/Jhon', function(userData) {
/* Display user with username 'Jhon' */
console.log(userData);
});
});
});
From the above code snippet, you can see that the code becomes harder to understand, harder to maintain, and harder to modify. This happens due to the nesting of all the callback functions.
How do you stop Callback Hell?
Multiple techniques can be used to avoid callback hell. They are as follows:
By using promises.
With the help of async,
By using the async.js library.
I have already discussed how to work with promises and how async await can be helpful to avoid callback hell.
By Using Async.js Library
Let's talk about working with the async.js library in order to avoid callback hell.
As per the official website of async.js, Async is a utility module that provides straightforward, powerful functions for working with asynchronous JavaScript.
Async.js provides about 70 functions in total. For now, we will discuss only two of them, i.e., async. waterfall() and async. series().
async.waterfall()
It is useful when you want to run some tasks one after the other and then pass the result from the previous task to the next task. It takes an array of functions called "tasks" and a final "callback" function that is called after all functions in the "tasks" array have been completed, or a "callback" is called with an error object.
var async = require('async');
async.waterfall([
function(callback) {
/*
Here, the first argument value is null, it indicates that
the next function will be executed from the array of functions.
If the value was true or any string then final callback function
will be executed, other remaining functions in the array
will not be executed.
*/
callback(null, 'one', 'two');
},
function(param1, param2, callback) {
// param1 now equals 'one' and param2 now equals 'two'
callback(null, 'three');
},
function(param1, callback) {
// param1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
/*
This is the final callback function.
result now equals 'done'
*/
});
async.series()
This function is helpful when you want to run functions and then need to get the results after all the functions have been executed successfully. The main difference between async.waterfall() and async.series() is that async.series() doesn't pass the data from one function to another.
async.series([
function(callback) {
// do some stuff ...
callback(null, 'one');
},
function(callback) {
// do some more stuff ...
callback(null, 'two');
}
],
// optional callback
function(err, results) {
// results is now equal to ['one', 'two']
});
Javascript Callback vs Closure
Closure
In technical terms, closure is the combination of functions that are bundled together and have references to their surrounding state.
Simply put, a closure allows access to an outer function's scope from an inner function.
To use a closure, we need to define a function inside another function. Then we need to return it or pass it to another function.
Callback
Conceptually, callbacks are similar to closures. A callback is basically where a function accepts another function as an argument.
Final Words
I hope this article clears up all your doubts about Javascript callback functions. If you find this article helpful, share it with others.
google.com, pub-6015689109374904, DIRECT, f08c47fec0942fa0