By Nilesh Sanyal
Translation: Crazy geek
Original text: dzone.com/articles/ja…
Reproduced without permission
JavaScript callbacks are an important concept to understand as a successful JavaScript developer. But I am confident that after reading this article, you will be able to overcome any previous obstacles to using the callback method.
Before we begin, let’s make sure we have a solid understanding of functions.
Quick review: JavaScript functions
What is a function?
A function is a logical artifact in which there is a set of code that performs a specific task. In fact, functions allow code to be written in a more organized way for ease of debugging and maintenance. Functions also allow code reuse.
Instead of writing the same code over and over again, you define a function once and then call it when you need it.
Declare a function
Now, let’s look at how to declare a function in javascript.
-
Use the constructor of a function: In this approach, the function is created with the help of the constructor of the function. Technically, this approach is less efficient than using function expression syntax and function declaration statement syntax to declare functions.
-
Use function expressions: This is usually the same as variable assignment. In short, the function body is treated as an expression, and that expression is assigned to a variable. Functions defined using this syntax can be named or anonymous.
A function without a name is called an anonymous function. Anonymous functions are self-calling, which means that they call themselves automatically. This behavior is also known as immediate function expression (IIFE).
-
Use function declarations: This is an old-school approach commonly used in JavaScript. After the keyword “function”, you must specify the name of the function. Later, if the function takes more than one argument or parameter, you need to mention them as well. Although this part is completely optional.
In the function body, the function must return a value to the caller. The function stops execution when a return statement is encountered. Inside the function, arguments will act as local variables.
Similarly, variables declared inside a function are local variables 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.
Call a function
The previously declared function is called in either of the following cases:
-
When an event occurs, for example, the user clicks a button, or the user selects some option from a drop-down list, and so on.
-
When you call this function from javascript code.
-
This function can be called automatically, as discussed in anonymous function expressions.
The () operator calls the function.
What is a callback function?
According to MDN, a callback function is a function that is passed as an argument to another function, and then performs some kind of operation by calling the callback function inside the external function.
Let me explain in human terms that a callback function is a function that is executed immediately after another function has finished executing. A callback function is a function passed as an argument to another JavaScript function. The callback function is executed inside the function passed.
Functions are treated as a class of objects in JavaScript. For a class of objects, we mean that exponents, functions, or variables can be the same as other entities in the language. As a class of objects, functions can be passed as variables to, or returned from, other functions.
Functions that can perform this operation are called higher-order functions. The callback function is actually a pattern. The word “pattern” denotes a proven approach to solving common problems in software development. It is best to use the callback function as a callback mode.
Why do we need a correction
Client-side JavaScript runs in the browser, and the browser’s main process is a single-threaded event loop. If we try to run a long-running operation in a single-threaded event loop, the process is blocked. This is technically bad because the process stops processing other events while waiting for the operation to complete.
For example, the alert statement is considered one of the blocking codes in javascript in the browser. If you run Alert, you won’t be able to interact in your browser until you close the Alert dialog window. To prevent blocking long-running operations, we use a callback.
Let’s dig a little deeper so you know exactly when to use callbacks.
In the code snippet above, the getMessage() function is executed first, followed by displayMessage(). Both display a message in the browser’s console window, and both execute immediately.
In some cases, some code will not execute immediately. For example, if we assume that the getMessage() function performs an API call, we must send the request to the server and wait for the response. What should we do about it?
How do I use callback functions
Instead of telling you the syntax of JavaScript callback functions, I think it’s better to implement them in the previous example. The modified code snippet is shown in the screenshot below.
In order to use the callback function, we need to perform some task that does not display the results immediately. To simulate this behavior, we use the JavaScript setTimeout() function. This function pauses for two seconds and then displays the message “Hi, there” in the console window.
“Displayed Messages” will be displayed in the browser’s console window. In this case, first we need to wait for the getMessage() function. After this function is successfully executed, the displayMessage() function is executed.
How callbacks work
Let me explain what happened behind the scenes in the previous example.
As you can see from the previous example, in the getMessage() function, we pass two arguments. The first argument is the MSG variable, which is displayed in the browser console window, and the second argument is the callback function.
Now, you might be wondering why the callback function is passed as an argument — to implement the callback function, we must pass one function as an argument to another.
After getMessage() completes its task, we call the callback function. Later, when the getMessage() function is called, the reference is passed to the displayMessage() function, which is the callback function.
Note that when the getMessage() function is called, we only pass its reference to the displayMessage() function. That’s why you won’t see the function call operator, the () symbol, next to it.
Are Javascript callbacks asynchronous?
JavaScript is considered a single-threaded scripting language. Single-threaded is when JavaScript executes one block of code at a time. When JavaScript is busy executing one block, it can’t move to the next.
In other words, we can think of JavaScript code as inherently blocking. But this block prevents us from writing code in cases where there is no way to get results immediately after performing certain tasks.
The tasks I’m talking about include the following:
- The data is retrieved by making API calls to certain endpoints.
- Get some resources (for example, text files, image files, binaries, etc.) from a remote server by sending a network request.
To handle these cases, asynchronous code must be written, and callback functions are one way to handle these cases. So essentially, callbacks are asynchronous.
Javascript callback hell
Callback hell occurs when multiple asynchronous functions are executed one after another. It is also known as the Pyramid of Doom.
Suppose you want to get a list of all Github users. Then search the user for the major contributors to the JavaScript library. Next, you want to get the details of the person named John from the user.
To do this with the help of callbacks, the code should look like this:
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);
});
});
});
Copy the code
As you can see from the code snippet above, the code becomes more difficult to understand and maintain and modify. This is caused by the nesting of callback functions.
How to avoid callback hell?
You can use a variety of techniques to avoid callback hell, as shown below.
- The use of promise
- With the help of async – await
- Using async. Js library
Using Async. Js library
Let’s talk about how to avoid callback hell with the async.js library.
Async is a utility module that provides direct and powerful functions to use asynchronous JavaScript, according to the async.js official website.
Async.js provides about 70 functions in total. For now, we will only discuss two of them, namely async.waterfall() and async.series().
async.waterfall()
This function is useful when you want to run tasks one after another and then pass the results from one task to the next. It requires a “task” array of functions and a final “callback” function, which will be called after all the functions in the “task” array have completed, or after the “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' */
});
Copy the code
async.series()
This is useful when you want to run a function and then need to retrieve the result after all the functions have successfully executed. The main difference between async.waterfall() and async.series() is that async.series() does not pass 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']});Copy the code
Javascript callbacks and closures
closure
In technical terms, a closure is a combination of functions bundled together, referencing the state around it.
In short, closures allow access to the scope of an outer function from an inner function.
To use closures, we need to define another function inside one function. We then need to return or pass it to another function.
The callback
Conceptually, callbacks are similar to closures. A callback is basically the use of one function as another.
The last word
Hopefully this article has cleared up any questions you might have about javascript callbacks. If you find this article helpful, please share it with others.