One of the advantages of JavaScript is how it handles asynchronous code. The asynchronous code is put into an event queue until all other code is executed, without blocking the thread. However, it may be difficult for beginners to write asynchronous code. And in this article, I will eliminate any confusion you may have.
Understanding Asynchronous Code
The most basic asynchronous functions of JavaScript are settimeout and setinterval. SetTimeout will execute the given function after a certain amount of time. It takes a callback function as the first parameter and a millisecond time as the second argument. The following are examples of usage:
Console.log ("a");
settimeout (function () {
console.log ("C")
}, +);
settimeout (function () {
console.log ("D")
};
settimeout (function () {
console.log ("E")
};
Console.log ("B");
As expected, the console first outputs "a", "B", and after about 500 milliseconds, see "C", "D", "E". I use "approx" because settimeout is in fact unpredictable. In fact, even the HTML5 specification mentions the problem:
- "This API does not guarantee that timing will run correctly as scheduled. Delays caused by CPU load, other tasks, and so on are predictable. ”
Interestingly, the timeout does not occur until all the rest of the code executes in the same program segment. So if you set a time-out and perform a function that takes a long time to run, the timeout does not even start until the function completes. In fact, asynchronous functions, such as settimeout and setinterval, are pressed into queues called event loop.
The Event loop is a callback function queue. When an asynchronous function executes, the callback function is pressed into the queue. The JavaScript engine does not begin processing the event loop until the asynchronous function completes. This means that JavaScript code is not multithreaded, even if the behavior behaves similarly. The event loop is an advanced first out (FIFO) queue, which means that callbacks are executed in the order in which they are queued. JavaScript is chosen by node as the development language because it's so easy to write code like this.
Ajax
Asynchronous JavaScript and XML (AJAX) permanently change the state of the JavaScript language. Suddenly, the browser no longer needs to reload to update the Web page. Implementing AJAX code in different browsers can be long and tedious, but thanks to the help of jquery (and other libraries), we can implement client-server communication in a very easy and elegant way.
We can use the jquery Cross-browser interface $.ajax to easily retrieve data, but it doesn't show what's happening behind the scenes. Like what:
var data;
$.ajax ({
URL: "SOME/URL/1",
success:function (data) {
//But, this will!
Console.log (data);
}
)
Oops, this won ' t work ...
Console.log (data);
The easiest mistake to make is to use data immediately after calling $.ajax, but this is actually the case:
Xmlhttp.open ("Get", "SOME/UR/1", true);
Xmlhttp.onreadystatechange = function (data) {
if (xmlhttp.readystate = = 4) {
console.log (data);
}
};
Xmlhttp.send (NULL);
The underlying XMLHttpRequest object initiates the request and sets the callback function to handle the XHR Readystatechnage event. Then execute the XHR send method. In XHR run, the ReadyStateChange event is triggered when its properties readystate changed, and the callback function triggers execution only when the XHR receives the response from the remote server.
Handling Asynchronous code
Asynchronous programming can easily fall into what we often call "a callback to Hell." Because in fact almost all asynchronous functions in JS use callbacks, the result of executing several asynchronous functions sequentially is the nested callback function and the complex code that comes with it.
Many of the functions in Node.js are also asynchronous. So the following code is basically common:
var fs = require ("FS");
Fs.exists ("Index.js", function () {
fs.readfile ("Index.js", "UTF8", function (err, contents) {
contents = Somefu Nction (contents); Do something with contents
fs.writefile ("Index.js", "UTF8", function () {
Console.log ("whew! Done finally ... ")
;}); Console.log ("Executing ...");
The following client code is also visible:
Gmaps.geocode ({
address:fromaddress,
callback:function (results, status) {
if (status = = "OK") {from
LATLNG = results[0].geometry.location;
Gmaps.geocode ({
address:toaddress,
callback:function (results, status) {
if (status = = "OK") {
Tolatl ng = results[0].geometry.location;
Map.getroutes ({
origin: [Fromlatlng.lat (), FROMLATLNG.LNG ()],
destination: [Tolatlng.lat (), TOLATLNG.LNG ()],
travelmode: "Driving",
Unitsystem: "Imperial",
callback:function (e) {
Console.log (" Annnnd FINALLY here ' s the directions ... ");
Do something with E}}};}}});
Nested callbacks can get really nasty, but there are several-solutions to this style of coding.
Nested callbacks can easily lead to "bad taste" in code, but you could try to solve the problem with the following styles
- The problem isn ' t with the language itself; It ' s with the way programmers to use the Language-async Javascript.
No bad language, only bad program ape--Asynchronous Javasript
named Functions
A convenient solution to clear nested callbacks is simply to avoid nesting over two layers. Passing a named function as a callback parameter instead of passing an anonymous function:
var fromlatlng, tolatlng;
var routedone = function (e) {
console.log ("Annnnd FINALLY here's directions ...");
Do something with e
};
var toaddressdone = function (results, status) {
if (status = = "OK") {
tolatlng = results[0].geometry.location;
map.getroutes ({
origin: [Fromlatlng.lat (), FROMLATLNG.LNG ()],
destination: [Tolatlng.lat (), TOLATLNG.LNG ()],
travelmode: "Driving",
Unitsystem: "Imperial",
callback:routedone
});
};
var fromaddressdone = function (results, status) {
if (status = = "OK") {
fromlatlng = Results[0].geometry.loc ation;
Gmaps.geocode ({
address:toaddress,
callback:toaddressdone
});
}
;
Gmaps.geocode ({
address:fromaddress,
callback:fromaddressdone
});
In addition, the Async.js library can help us deal with multiple Ajax requests/responses. For example:
Async.Parallel ([
function (done) {
Gmaps.geocode ({
address:toaddress,
callback:function (Result) { Done
(null, result);
}
);
}, the
function (done) {
Gmaps.geocode ({
address:fromaddress ,
callback:function (result) {do
(null, result);
}}
], function (errors, Results) {
getroute (results[0], results[1]);
This code executes two asynchronous functions, each receiving a callback function named "Done" and calling it at the end of the function. When the two "done" callback function is finished, the callback function of the parallel function is called and executes or handles the results or errors produced by the two asynchronous functions.
Promises model
Quote from commonjs/a:
- Promise represents the final result of an operation being returned after it has been completed independently.
There are many libraries that contain the Promise model, where jquery already has a good promise API to use. jquery introduced the deferred object in version 1.5 and can use Jquery.deferred's constructed results in functions that return promise. A function that returns promise is used to perform some kind of asynchronous operation and resolve the delay after completion.
var geocode = function (address) {
var DFD = new $. Deferred ();
Gmaps.geocode ({
address:address,
callback:function (response, status) {return
dfd.resolve (response); c6/>}
});
return Dfd.promise ();
};
var getroute = function (FROMLATLNG, tolatlng) {
var DFD = new $. Deferred ();
Map.getroutes ({
origin: [Fromlatlng.lat (), FROMLATLNG.LNG ()],
destination: [Tolatlng.lat (), TOLATLNG.LNG ()],
travelmode: "Driving",
Unitsystem: "Imperial",
callback:function (e) {return
dfd.resolve ( e);
}
);
return Dfd.promise ();
};
var dosomethingcoolwithdirections = function (route) {
//do something with Route
};
$.when (GeoCode (fromaddress), GeoCode (toaddress)).
Then (function (FROMLATLNG, tolatlng) {
getroute (FROMLATLNG, TOLATLNG). then (dosomethingcoolwithdirections); c29/>});
This allows you to execute two asynchronous functions, wait for their results, and then execute another function with the results of the previous two invocations.
- Promise represents the final result of an operation being returned after it has been completed independently.
In this code, the GeoCode method executes two times and returns a promise. The asynchronous function executes, and the resolve is invoked in its callback. Then, once the two call resolve completes, then will execute and receive the return results of the previous two call GeoCode. After the result is passed into Getroute, this method also returns a promise. Eventually, when Getroute's promise is resolved, the dosomethingcoolwithdirections callback executes.
Event
an event is another way of communicating when an asynchronous callback completes processing. An object can become a transmitter and distribute events, while another object listens to these events. This type of event handling method is called the Observer pattern. The Backbone.js library creates such a functional module in withbackbone.events.
var Somemodel = Backbone.Model.extend ({
URL: "/someurl"
});
var Someview = Backbone.View.extend ({
initialize:function () {
this.model.on ("Reset", This.render, this);
This.model.fetch ();
},
render:function (data) {
//do something with Data
}
};
var view = new Someview ({
model:new Somemodel ()
});
There are other mixed examples and function libraries for launching events, such as the JQuery event emitter, Eventemitter, Monologue.js, and the Eventemitter modules built in Node.js.
- An event loop is a queue of callback functions.
A similar way of distributing messages is called the broker pattern, which is used in the Postal.js library. In mediator mode, there is a middleman for all objects to listen and distribute events. In this mode, an object is not directly associated with another object, thus separating the objects from each other.
Never return promise to a common API. This not only concerns the use of API users to promises, but also makes refactoring more difficult. However, the combination of internal use promises and external interface events can make applications less coupled and easier to test.
In the previous example, the dosomethingcoolwithdirections callback function executes after two geocode functions have been completed. Dosomethingcoolwithdirections then receives the response from the Getroute and sends it out as a message.
var dosomethingcoolwithdirections = function (route) {
postal.channel ("UI"). Publish ("Directions.done", {
Route:route
});
This allows other parts of the application to respond to an asynchronous callback without directly referencing the object that generated the request. When you get the command, it's likely that many areas of the page will need to be updated. In a typical jquery Ajax process, a smooth callback may have to be adjusted when the commands that are received change. This may make the code difficult to maintain, but by using messages, it is much simpler to handle updates for multiple areas of the UI.
var UI = function () {
This.channel = Postal.channel ("UI");
This.channel.subscribe ("Directions.done", This.updatedirections). Withcontext (this);
UI.prototype.updateDirections = function (data) {
//The route is available on Data.route and now just update the ui
};
App.ui = new UI ();
Other libraries that deliver messages based on intermediary mode are amplify, PUBSUBJS, and Radio.js.
Conclusion
JavaScript makes it easy to write asynchronous code. Use promises, events, or named functions to avoid "callback hell". To get more JavaScript asynchronous programming information, click Async javascript:build more responsive Apps with less. More instances hosted on the GitHub, address Nettutsasyncjs, quickly clone it!