📜 ⬆️ ⬇️

Understanding callback functions (callbacks)

Callback functions are extremely important in the Javascript language. They are almost everywhere. But, despite the experience of programming in C / Java, I had difficulties with them (as with the very idea of ​​asynchronous programming), and I decided to figure it out. Strange, but I couldn’t find good introductory articles on callback functions on the Internet - mostly there were excerpts of documentation on call() and apply() functions or short pieces of code that demonstrate their use, and now, having stuffed cones in search of truth, I I decided to write an introduction to the callback function myself.

Functions are objects


To understand callback functions, you need to understand ordinary functions. This may seem commonplace, but functions in Javascript are a bit weird.

Functions in Javascript are actually objects. Namely, the objects of the Function class created by the Function constructor. The Function object contains a string with the JS code of this function. If you have moved from C or Java, this may seem strange (how can the code be a string ?!), but generally speaking, in Javascript this is very often. The distinction between code and data is sometimes blurred.

 //   ,    Function    var func_multiply = new Function("arg1", "arg2", "return arg1 * arg2;"); func_multiply(5, 10); // => 50 

')
The advantage of the concept of "function-as-object" is that the code can be transferred to another function in the same way as a normal variable or object (because literally code is just an object).

Passing a function as a callback function


Passing a function as an argument is simple.

 //      callback function some_function(arg1, arg2, callback) { // ,       arg1  arg2 var my_number = Math.ceil(Math.random() * (arg1 - arg2) + arg2); //       callback,     callback(my_number); } //   some_function(5, 15, function (num) { //       callback- console.log("callback called! " + num); }); 


It may seem folly to create such an overly sophisticated code when you can return a value in a normal way, but there are situations in which it is impractical and callback functions are needed.

Do not block the exit


Traditionally, functions in the course of execution accept arguments as input and return a value using the return expression (ideally, the only return expression at the end of the function is one entry point and one exit point). It makes sense. Functions are essentially routes between input and output.

Javascript makes it possible to do things a little differently. Instead of waiting for the function to finish executing and returning a value, we can use callback functions to get it asynchronously. This is useful for cases when it takes a lot of time to complete, for example, with AJAX requests, because we can not pause the browser. We can continue to do other things while waiting for a callback call. In fact, very often we are required (or rather, we are strongly recommended) to do everything asynchronously in Javascript.

Here is a more detailed example that uses AJAX to load an XML file and uses the call() function to call a callback function in the context of the requested object (this means that when we specify this inside the callback function, it will refer to the requested an object):

 function some_function2(url, callback) { var httpRequest; //   XMLHttpRequest- if (window.XMLHttpRequest) { httpRequest = new XMLHttpRequest(); } else if (window.ActiveXObject) { //   Internet Explorer' httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); } httpRequest.onreadystatechange = function () { //       //       if (httpRequest.readyState === 4 && httpRequest.status === 200) { callback.call(httpRequest.responseXML); //   } }; httpRequest.open('GET', url); httpRequest.send(); } //   some_function2("text.xml", function () { console.log(this); }); console.log("    "); 


In this example, we create an httpRequest object and load the XML file. The typical paradigm of returning a value at the end of a function does not work here anymore. Our request is processed asynchronously, which means that we start the request and tell it to call our function as soon as it ends.

We use two anonymous functions here. It is important to remember that it would not be difficult for us to use named functions, but in the name of brevity, we made them nested. The first anonymous function is executed whenever the status changes in our httpRequest object. We ignore this until the status is 4 (i.e., the request is completed) and the status is 200 (i.e., the request is successful). In the real world, you would like to check if the request failed, but we assume that the file exists and can be loaded by the browser. This anonymous function is associated with httpRequest.onreadystatechange, so it does not execute immediately, but is called every time a state changes in our request.

When we finally complete our AJAX request, we do not just run the callback function, we use the call() function to do this. This is another way to call a callback function. The method we used before - a simple start of a function here would work well, but I thought it worth exploring the use of the call() function. Alternatively, you can use the apply() function (a discussion of the difference between it and call() beyond the scope of this article, I will only say that this affects the way the function arguments are passed).

In using call() great that we ourselves set the context in which the function is executed. This means that when we use the this inside our callback function, it refers to the fact that we pass the first argument to call() . In this example, when we referenced this inside our anonymous function, we referenced the responseXML received as the result of an AJAX request.

Finally, the second console.log expression will be executed first, because the callback function is not executed until the request is completed, and until that happens, the subsequent parts of the code continue to be quietly executed.

Wrap it up


I hope you now understand callback functions well enough to start using them in your own code. It is still difficult for me to structure the code that is based on callback functions (eventually it becomes like spaghetti ... my mind is too used to ordinary structured programming), but they are a very powerful tool and one of the most interesting parts of the Javascript language.

Source: https://habr.com/ru/post/151716/


All Articles