Understanding and using callback functions in JavaScript
Http://javascriptissexy.com/
In JavaScrip, function is a built-in class Object, that is, it is a type Object and can be used for management of built-in objects like other String, Array, Number, and Object objects. Because a function is actually an object, it can be "stored in a variable, passed to (another) function through parameters, and created inside the function, return the result value from the function ". Because function is a built-in object, we can pass it as a parameter to another function, delay it to be executed in the function, or even return it after execution. This is the essence of using callback functions in JavaScript. The rest of this article will fully learn JavaScript callback functions. Callback functions may be the most widely used functional programming technology in JavaScript. Maybe only a small segment of JavaScript or jQuery code will leave a mysterious feeling for developers. After reading this article, it may help you eliminate this mystery.
Callback FunctionFrom a famous programming paradigm --Functional ProgrammingFunction programming specifies the function parameters. Although function-based programming has become more widely used, it has been regarded by "Professional and intelligent" programmers as a hard-to-understand technology. Previously, it will be like this in the future.
Fortunately, functional programming has already been explained so that ordinary people like you and me can understand and use it. One of the most important techniques of functional programming is the callback function. You will soon read that implementing the callback function is as simple as passing common parameter variables. This technology is so simple that I doubt why it is often included in JavaScript high-level topics.
What are callback or advanced functions?
A callback function is considered an advanced function. A callback function is an advanced function that is passed as a parameter to another function (called otherFunction, the callback function is called (or executed) in otherFunction ). The essence of a callback function is a mode (a mode to solve common problems). Therefore, a callback function is also called a callback mode.
Consider the following callback functions commonly used in jQuery:
//Note that the item in the click method's parameter is a function, not a variable.//The item is a callback function$("#btn_1").click(function() { alert("Btn 1 Clicked");});
As shown in the previous example, we passed a function to the form parameter of the click method, and the click method will call (or execute) the callback function we passed to it. This example provides a typical method for using callback functions in JavaScript and is widely used in jQuery.
Let's take a closer look at another typical example of basic JavaScript:
var friends = ["Mike", "Stacy", "Andy", "Rick"];friends.forEach(function (eachName, index){console.log(index + 1 + ". " + eachName); // 1. Mike, 2. Stacy, 3. Andy, 4. Rick});
Once again, an anonymous function (a function without a function name) is passed to the forEach method as a parameter of forEach.
So far, we have passed an anonymous function as a parameter to another function or method. Before looking at other more complex callback functions, let's take a look at the working principle of callback and implement our own callback function.
How is the callback function implemented?
We can use a function as a variable, as a parameter of another function, as a return result in another function, and call it in another function. When we pass a callback function to another function as a parameter, we only pass the definition of this function and do not execute it in the parameter.
When a include (CALL) function has a callback function defined in the parameter, it can call (that is, callback) it at any time.
This indicates that the callback function is not executed immediately, but is called back at the specified position in the body of the function containing the function (such as its name ). Therefore, even if the first jQuery example looks like this:
//The anonymous function is not being executed there in the parameter. //The item is a callback function$("#btn_1").click(function() { alert("Btn 1 Clicked");});
The anonymous function will be called in the function body of the click function. Even if there is no name, it can be accessed by the included function through the arguments object.
The callback function is a closure.
When a callback function is passed as a parameter to another function, the callback function will be executed somewhere in the body of the function, just as the callback function is defined in the body of the function that contains the function. This means that the callback function is a closure. To learn more about the closure, please refer to the author's post on Understand JavaScript Closures With closure. From the defined function, the closure function can access the scope of the included function. Therefore, the callback function can access the variables containing the function, or even global variables.
Basic principles for implementing callback Functions
To put it simply, you need to follow several principles when implementing the callback function.
Use the namefunction or anonymous function as the callback
In the previous jQuery and forEach examples, we defined anonymous functions in parameters containing functions, which is one of the common forms of using callback functions, another commonly used form is to define a function with a name and pass the function name as a parameter to another function. For example:
?// global variablevar allUserData = [];// generic logStuff function that prints to consolefunction logStuff (userData) { if ( typeof userData === "string") { console.log(userData); } else if ( typeof userData === "object") { for (var item in userData) { console.log(item + ": " + userData[item]); } }}// A function that takes two parameters, the last one a callback functionfunction getInput (options, callback) { allUserData.push (options); callback (options);}// When we call the getInput function, we pass logStuff as a parameter.// So logStuff will be the function that will called back (or executed) inside the getInput functiongetInput ({name:"Rich", speciality:"JavaScript"}, logStuff);// name: Rich// speciality: JavaScript
Passing parameters to the callback function
Because the callback function is the same as a general function during execution, we can pass parameters to it. You can use any attribute (or global attribute) that contains the function as a parameter to pass the callback function. In the previous example, we passed the options containing the function as a parameter to the callback function. The following example shows how to pass a global or local variable to the callback function:
//Global variablevar generalLastName = "Clinton";function getInput (options, callback) { allUserData.push (options);// Pass the global variable generalLastName to the callback function callback (generalLastName, options);}
Make sure that the callback is a function before execution.
Before calling, it is usually wise to make sure that the callback passed through the parameter is a required function. In addition, making callback functions optional is also a good practice.
Let's refactor the getInput function in the above example to ensure that the callback function has been properly checked.
function getInput(options, callback) { allUserData.push(options); // Make sure the callback is a function if (typeof callback === "function") { // Call it, since we have confirmed it is callable callback(options); }}
If the getInput function does not perform a proper check (check whether callback is a function or whether it is passed in through a parameter), our code will cause a runtime error.
Problems with using callback functions containing this object
When a callback function is a method containing this object, we must modify the method for executing the callback function to protect the content of this object. Otherwise, this object will point to the global window object (if the callback function is passed to the global function) or to the include function. Let's take a look at the following code:
// Define an object with some properties and a method// We will later pass the method as a callback function to another functionvar clientData = { id: 094545, fullName: "Not Set", // setUserName is a method on the clientData object setUserName: function (firstName, lastName) { // this refers to the fullName property in this object this.fullName = firstName + " " + lastName; }}function getUserInput(firstName, lastName, callback) { // Do other stuff to validate firstName/lastName here // Now save the names callback (firstName, lastName);}
In the following sample code, when clientData. setUserName is executed, this. fullName does not set the attribute fullName in the clientData object, but sets fullName in the window object because getUserInput is a global function. This occurs because the this object points to the window object in the global function.
getUserInput ("Barack", "Obama", clientData.setUserName);console.log (clientData.fullName);// Not Set// The fullName property was initialized on the window objectconsole.log (window.fullName); // Barack Obama
Use the Call or Apply function to protect this object
We can solve the problem in the previous example by using the Call or Apply function. So far, we know that every function in JavaScript has two methods: Call and Apply. These methods can be used to set the content of this object inside the function and pass the content to the object pointed to by function parameters.
CallTakes the value to be used as the this object inside the function as the first parameter, and the remaining arguments to be passed to the function are passed individually (separated by commas of course ). the Apply function's first parameter is also the value to be used as the thisobject inside the function, while the last parameter is an array of values (or the arguments object) to pass to the function. (This section is too easy to translate. Let's talk about it in the original article)
This sounds complicated, but let's see how easy it is to use Apply and Call. To solve the problem in the previous example, we use the Apply function as follows:
//Note that we have added an extra parameter for the callback object, called "callbackObj"function getUserInput(firstName, lastName, callback, callbackObj) { // Do other stuff to validate name here // The use of the Apply function below will set the this object to be callbackObj callback.apply (callbackObj, [firstName, lastName]);}
The Apply function correctly sets this object. Now we can correctly execute the callback function and correctly set the fullName attribute in the clientData object.
// We pass the clientData.setUserName method and the clientData object as parameters. The clientData object will be used by the Apply function to set the this object?getUserInput ("Barack", "Obama", clientData.setUserName, clientData);// the fullName property on the clientData was correctly setconsole.log (clientData.fullName); // Barack Obama
We can also use the Call function, but in this example we use the Apply function.
Multiple callback functions are also allowed.
We can pass multiple callback functions to another function, just like passing multiple variables. This is a typical example of AJAX functions using jQuery:
function successCallback() { // Do stuff before send}function successCallback() { // Do stuff if success message received}function completeCallback() { // Do stuff upon completion}function errorCallback() { // Do stuff if error received}$.ajax({ url:"http://fiddle.jshell.net/favicon.png", success:successCallback, complete:completeCallback, error:errorCallback});
"Callback to hell" Problems and Solutions
Asynchronous code execution is a simple method of execution in any order. Sometimes there are many levels of callback functions that you may look like the following code. The following messy code is called "Callback hell" because it is a troublesome code that contains a lot of callbacks. I saw this example in node-mongodb-native. The MongoDB driver Node. js. sample code is like this:
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) { collection.insert({'a':1}, function(err, docs) { collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) { cursor.toArray(function(err, items) { test.assertEquals(1, items.length); // Let's close the db p_client.close(); }); }); }); }); });});
You are unlikely to encounter this problem in your own code, but if you encounter (or encounter it later), there are two ways to solve this problem.
- Name and define your function, and then pass the function name as the callback, instead of defining an anonymous function in the parameter list of the main function.
- Modularization: divides your code into modules, so that you can leave a part of the code block for special work. Then you can introduce this model into your large applications.
??
Implement your own callback functionNow you fully understand (I believe you have understood it. If not, please read it again quickly) the features of JavaScript For callback and the usage of callback is so simple but powerful. You should check whether your code has the opportunity to use the callback function. You can consider using the callback when you have the following requirements:
- Avoid repeated code (DRY-Do Not Repeat Yourself)
- Better abstraction (processing various types of Functions) where you need more common functions ).
- Enhance code maintainability
- Enhance code readability
- More customized Functions
It is very easy to implement your own callback function. In the following example, I can create a function to get user data and generate a general poem using user data, welcome users with user data, but this function will be a messy function, where if/else judgment is everywhere, there may even be many restrictions and other functions that the application may need to process user data cannot be executed.
Instead, I added a callback function to the implementation, in this way, after obtaining user data, the main function can pass the full user name and gender to the callback function parameters and execute the callback function to complete any task.
In short, the getUserInput function is generic and can execute multiple callback functions with various functions.
// First, setup the generic poem creator function; it will be the callback function in the getUserInput function below.function genericPoemMaker(name, gender) { console.log(name + " is finer than fine wine."); console.log("Altruistic and noble for the modern time."); console.log("Always admirably adorned with the latest style."); console.log("A " + gender + " of unfortunate tragedies who still manages a perpetual smile");}//The callback, which is the last item in the parameter, will be our genericPoemMaker function we defined above.function 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 pass the genericPoemMaker function as the callback:
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 only processes user data input, we can pass any callback function to it. For example, we can pass a greetUser function like this.
function greetUser(customerName, sex) { var salutation = sex && sex === "Man" ? "Mr." : "Ms."; console.log("Hello, " + salutation + " " + customerName);}// Pass the greetUser function as a callback to getUserInputgetUserInput("Bill", "Gates", "Man", greetUser);// And this is the outputHello, Mr. Bill Gates
Like in the previous example, we call the same getUserInput function, but this time we executed a completely different task.
As you can see, callback functions provide a wide range of functions. Although the example mentioned above is very simple, when you start to use the callback function, think about how much work you can save and how to better abstract your code. Come on! Think about it when you get up in the morning, think about it before going to bed at night, and think about it when you are resting ......
When using callback functions in JavaScript, pay attention to the following points, especially in the development of web applications, in third-party libraries and frameworks.
- Asynchronous execution (such as reading files and sending HTTP requests)
- Event monitoring and Processing
- Set timeout and interval
- Generalization: concise code