SoFunction
Updated on 2025-02-28

Understanding and using callback functions in JavaScript

Overview

In JavaScript, functions are first-class objects, which means that functions can be managed in accordance with first-class management like objects. Since functions are actually objects: they can be "stored" in variables, passed as function parameters, created in functions, and returned from functions.

Because functions are the first type of objects, we can use callback functions in JavaScript. In the following article, we will learn about all aspects of callback functions. Callback functions are probably the most used functional programming trick in JavaScript, and while they literally seem to be a small piece of JavaScript or jQuery code, it is still a mystery to many developers. After reading this article, you can learn how to use callback functions.

Callback functions are concepts derived from a programming paradigm called functional programming. Simply put, functional programming is about using functions as variables. Functional programming used to be - and even now, still not widely used - it used to be regarded as the secret skill of franchise-trained, master-level programmers.

Fortunately, the tricks of function-is-programming have been fully articulated now so ordinary people like me and you can also use it easily. A major skill in functional programming is callback functions. In the following content, you will find that implementing a callback function is actually as simple as passing parameters to ordinary functions. This technique is so simple that I often feel strange why it is often included in chapters that tell advanced JavaScript skills.

What is a callback or a higher-order function

A callback function, also known as a higher-order function, is a function that is passed as a parameter to another function (here we call another function otherFunction), and the callback function is called in otherFunction. A callback function is essentially a programming mode (a solution created for a common problem), so using a callback function is also called a callback mode.

Here is a simple and common example of using callback functions in jQuery:

//Note that the click method is a function instead of a variable//It's the callback function$("#btn_1").click(function() {
    alert("Btn 1 Clicked");
});

As you can see in the previous example, we pass a function as an argument to the click method. The click method calls (or executes) the function we pass to it. This is a typical usage of callback functions in JavaScript, which is widely used in jQuery.

Here is another example of a typical callback function in JavaScript:

var friends = ["Mike", "Stacy", "Andy", "Rick"];

(function (eachName, index){
    (index + 1 + ". " + eachName); // 1. Mike, 2. Stacy, 3. Andy, 4. Rick
});

Again, I noticed that we are talking about an anonymous function (a function without a name) being passed as a parameter to the forEach method.

So far, we have passed anonymous functions as arguments to another function or method. Before we look at more practical examples and write our own callback functions, let's understand how the callback functions work.

How does the callback function work?

Because functions are the first type of objects in JavaScript, we treat functions like objects, so we can pass functions like passing variables, return functions in functions, and use functions in other functions. When we pass a callback function as an argument to another function, we just pass the function definition. We are not executing the function in the arguments. We do not pass functions that carry a pair of parentheses() like we usually execute functions.

It is important to note that the callback function will not be executed immediately. It will be "callbacked" at a specific point in time within the function containing it (just like its name). So even the first jQuery example looks like this:

//Anonymous functions will not be executed in the parameters//This is a callback function$("#btn_1").click(function(){
    alert("Btn 1 Clicked");
});

This anonymous function will be called later in the function body. Even if there is a name, it is still obtained through the arguments object within the function containing it.

The callback function is a closure

When a callback function is passed as a variable to another function, the callback function is executed at a certain point in the function containing it, just as if the callback function was defined in the function containing it. This means that the callback function is essentially a closure.

As we know, a closure can enter the scope of the function that contains it, so the callback function can get variables in the function that contains it, as well as variables in the global scope.

Basic principles of implementing callback functions

Callback functions are not complicated, but before we start creating and using callback functions, we should be familiar with several basic principles for implementing callback functions.

Use named or anonymous functions as callbacks

In the previous jQuery example and forEach example, we use an anonymous function defined at the parameter position as the callback function. This is a common magic trick in callback function use. Another common pattern is to define a named function and pass the function name to the function as a variable. For example, the following example:

//Global variablesvar allUserData = [];

//Ordinary logStuff function prints content to the consolefunction logStuff (userData){
    if ( typeof userData === "string"){
        (userData);
    } else if ( typeof userData === "object"){
        for(var item in userData){
            (item + ": " + userData[item]);
        }
    }
}

//A function that receives two parameters, the latter one is a callback functionfunction getInput (options, callback){
    (options);
    callback(options);
}

//When we call the getInput function, we pass logStuff to it as a parameter// Therefore logStuff will be called back (or executed) within the getInput functiongetInput({name:"Rich",speciality:"Javascript"}, logStuff);
//name:Rich
//speciality:Javascript

Pass parameters to callback function

Since the callback function is just a normal function when executed, we can pass parameters to it. We can pass any property (or global property) of the function that contains it as a parameter to the callback function. In the previous example, we passed options as an argument to the callback function. Now we pass a global variable and a local variable:

//Global variablesvar generalLastName = "Cliton";

function getInput (options, callback){
     (options);
    //Pass the global variable generalLastName to the callback function    callback(generalLastName,options);
}

Make sure the callback function is a function before execution

It is wise to check that the callback function passed as an argument before calling is indeed a function. At the same time, this is also the best time to implement a conditional callback function.

Let's refactor the getInput function in the example above to make sure the check is appropriate.

function getInput(options, callback){
    (options);
    
    //Make sure callback is a function    if(typeof callback === "function"){
        //Call it, now that we have determined that it is callable        callback(options);
    }
}

If there is no proper check, if there is no callback function in the getInput parameter or the passed callback function is actually not a function, our code will cause a run error.

Problem when using this object's method as a callback function

When the callback function is a method of this object, we must change the method of executing the callback function to ensure the context of this object. Otherwise, if the callback function is passed to a global function, this object either points to the global window object (in the browser). Or point to the object containing the method.

We explain in the following code:

//Define an object with some properties and a method //We will then pass the method as a callback function to another function
var clientData = {
    id: 094545,
    fullName "Not Set",
    //setUsrName is a method in clientData object    setUserName: fucntion (firstName, lastName){
        //This points to the fullName property in the object         = firstName + " " + lastName;
    }
} 

function getUserInput(firstName, lastName, callback){
    //What to do here to confirm firstName/lastName    //Storage names now    callback(firstName, lastName);
}

In your code example below, when executed, the fullName property in the clientData object is not set. Instead, it will set the fullName property in the window object, because getUserInput is a global function. This is because this object in the global function points to the window object.

getUserInput("Barack","Obama",);
(clientData,fullName);  //Not Set
//The fullName property will be initialized in the window object();  //Barack Obama

Use Call and Apply functions to save this

We can use Call or Apply functions to fix your problem above. So far, we know that every function in JavaScript has two methods: Call and Apply. These methods are used to set this object inside the function and to pass variables to this function.

The first parameter received by the call is an object used as this inside the function, and the parameters passed to the function are passed one by one (of course, using commas to separate). The first parameter of the Apply function is also used as this object inside the function, but the last parameter is indeed an array of values ​​passed to the function.

Sounds complicated, so let's see how easy it is to use Apply and Call. To fix the problem with the previous example, I will use the Apply function in your example below:

//Note that we have added new parameters as callback object called "callbackObj"function getUserInput(firstName, lastName, callback. callbackObj){
    //What to do here to confirm the name    (callbackObj, [firstName, lastName]);
}

This object is correctly set using the Apply function. We have now correctly executed the callback and correctly set the fullName property in the clientData object:

//We use the method and clientData object as parameters, and the clientData object will be used by the Apply method to set this objectgetUserName("Barack", "Obama", , clientData);

//The fullName property in clientData is set correctly(); //Barack Obama

We can also use the Call function, but in this example we use the Apply function.

Allow multiple callback functions

We can pass more than one callback function as arguments to a function, just as we can pass more than one variable. Here is an example of AJAX in jQuery:

function successCallback(){
    // Do something before sending}
  
function successCallback(){
//Do something after the message is successfully received}

function completeCallback(){
//Do something after you finish}

function errorCallback(){
    // Do something when an error occurs}

$.ajax({
    url:"/",
    success:successCallback,
    complete:completeCallback,
    error:errorCallback
});

"Callback Hell" problem and solutions

When executing asynchronous code, no matter what order the code is executed simply, it often becomes a pile of callback functions at many levels, so that the code becomes the following situation. These messy codes are called callback hell because there are too many callbacks, making it very difficult to understand the code. I took an example from node-mongodb-native, a MongoDB driver suitable for. This code below will fully illustrate the callback hell:

var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}), 
                 {'pk':CustomPKFactory});
p_client.open(function(err, p_client) {
    p_client.dropDatabase(function(err, done) {
        p_client.createCollection('test_custom_key', function(err, collection) {
            ({'a':1}, function(err, docs) {
                ({'_id':new ObjectID("aaaaaaaaaaaa")}, 
                function(err, cursor) {
                    (function(err, items) {
                        (1, );
                        // Let's close the db
                        p_client.close();
                    });
                });
            });
        });
    });
});

You should not want to encounter such problems in your code when you encounter

  • You will encounter this situation from time to time
  • Here are two solutions to this problem.
  • Name your functions and pass their names as callback functions instead of defining anonymous functions in the main function's parameters.
  • Modular L separates your code into modules so you can do specific tasks everywhere. You can then import the modules in your giant application.

Create your own callback function

Now that you have fully understood everything about callback functions in JavaScript (I think you already understand it if it's not as fast as rereading so as to), you see that using callback functions is so simple and powerful, you should look at your code to see if there is any place to use callback functions. The callback function will help you in the following aspects:

  • Avoid repeating code (DRY-Don't repeat yourself)
  • Implement better abstraction where you have more versatile functions (still keep all functions)
  • Make the code better maintainable
  • Make the code easier to read
  • Write more functions for specific functions

Creating your callback function is very simple. In the following example, I will create a function to do the following: read user information, create a common poem with data, and welcome the user. This is originally a very complex function because it contains many if/else statements and it will have many limitations and incompatibility in calling the functions required by user data.

Instead, I implemented the addition function with the callback function, so that the main function that gets user information can complete any task by simply passing the user's full name and gender as parameters to the callback function and executing it.

Simply put, the getUserInput function is multifunctional: it can execute callback functions with no functions.

//First, create a generic poem generation function; it will serve as a callback function for the getUserInput function below
function genericPoemMaker(name, gender) {
    (name + " is finer than fine wine.");
    ("Altruistic and noble for the modern time.");
    ("Always admirably adorned with the latest style.");
    ("A " + gender + " of unfortunate tragedies who still manages a perpetual smile");
}

//callback, the last item of the parameter will be the genericPoemMaker function we defined abovefunction getUserInput(firstName, lastName, gender, callback) {
    var fullName = firstName + " " + lastName;
    // Make sure the callback is a function
    if (typeof callback === "function") {
    // Execute the callback function and pass the parameters to it
    callback(fullName, gender);
    }
}

Call the getUserInput function and use the genericPoemMaker function as the callback function:

getUserInput("Michael", "Fassbender", "Man", genericPoemMaker);
// Output/* Michael Fassbender is finer than fine wine.
Altruistic and noble for the modern time.
Always admirably adorned with the latest style.
A Man of unfortunate tragedies who still manages a perpetual smile.
*/

Because the getUserInput function is only responsible for extracting data, we can pass any callback function to it. For example, we can pass a greetUser function:

unction greetUser(customerName, sex)  {
    var salutation  = sex && sex === "Man" ? "Mr." : "Ms.";
    ("Hello, " + salutation + " " + customerName);
}

// Use greetUser as a callback functiongetUserInput("Bill", "Gates", "Man", greetUser);

// Here is the outputHello, Mr. Bill Gates

We called the exact same getUserInput function, but this time we completed a completely different task.

As you can see, the callback function is amazing. Even if the previous example is relatively simple, imagine how much work you can save, your code will become more abstract, all of which requires you to start using the ruined function. Use it boldly.

Callback functions are often used in several ways in JavaScript programming, especially in modern web application development and libraries and frameworks:

  • Asynchronous calls (such as reading files, making HTTP requests, etc.)
  • Time listener/processor
  • setTimeout and setInterval methods
  • General: Simplified code

Conclusion

JavaScript callback functions are wonderful and powerful, and they provide many benefits to your web applications and code. You should use it when you have a requirement; or use callback functions to refactor your code for the sake of abstraction, maintainability, and readability of your code.

The above is the detailed content of understanding and using callback functions in JavaScript. For more information about JavaScript, please pay attention to my other related articles!