This article describes in detail the classification of node. js asynchronous programming and the problems existing in asynchronous programming, which are very detailed and meticulous. We recommend this article to our friends. Currently, a large number of asynchronous operations are required, and actual pages are more and more inclined to be single-page applications. Backbone, angular, knockout and other frameworks will be used in the future, but the question about asynchronous programming is the first question to be faced. With the rise of node, asynchronous programming has become a very hot topic. After a period of study and practice, I will summarize some details of asynchronous programming.
1. Classification of asynchronous programming
Methods To solve asynchronous problems include direct callback, pub/sub mode (Event Mode), asynchronous library control library (such as async, when), promise, and Generator.
1.1 callback function
Callback functions are commonly used to resolve Asynchronization. They are often used and easy to understand and can be easily implemented in libraries or functions. This is also a frequently used method for asynchronous programming.
However, the callback function has the following problems:
1. The nested pyramid may be formed, and the code is not easy to read;
2. Only One callback function can be matched, which is a limitation in many scenarios.
1.2 pub/sub mode (Event)
This mode is also called the event mode. It is an event-based callback function and is very common in class libraries such as jQuery.
The event publishing subscriber mode does not involve synchronous and asynchronous calls. However, in node, emit calls are triggered asynchronously along with the event loop. This mode is often used to decouple the business logic. The event publisher does not need to pay attention to the registered callback function or the number of callback functions. data can be transferred flexibly through the message method.
The advantages of this mode are: 1. easy to understand; 2. It is no longer limited to a callback function.
In poor cases: 1. Class Libraries are needed; 2. The order of events and callback functions is very important.
The Code is as follows:
Var img = document. querySelect (# id );
Img. addEventListener ('load', function (){
// Image Loading completed
......
});
Img. addEventListener ('error', function (){
// An error occurred.
......
});
The above code has two problems:
A. The load callback function is bound only when the img has been loaded. The result callback is not executed, but you still want to execute the corresponding callback function.
The Code is as follows:
Var img = document. querySelect (# id );
Function load (){
...
}
If (img. complete ){
Load ();
} Else {
Img. addEventListener ('load', load );
}
Img. addEventListener ('error', function (){
// An error occurred.
......
});
B. Exceptions cannot be handled properly.
Conclusion: The event mechanism is most suitable for handling repeated events on the same object. It does not need to be considered when events occur before the callback function is bound.
1.3 asynchronous control library
Currently, asynchronous libraries mainly include Q, when. js, win. js, And RSVP. js.
These libraries are characterized by linear code that can be written from top to bottom, in line with natural habits.
Bad things also have different styles, which are not easy to read and increase learning costs.
1.4 Promise
After the Promise is translated into Chinese, it is a commitment that, after the asynchronous process is completed, an external result (success or failure) will be given and the result will not be changed. In other words, Promise reflects the final returned result value of an operation (A promise represents the eventual value returned from the single completion of an operation ). Currently, Promise has been introduced into ES6 standards. Chrome, firefox, and other advanced browsers have implemented this native method internally, which is quite convenient to use.
The following describes the features of Promise from the following aspects:
1.4.1 status
Three States are available: pending, fulfilled, and rejected. Only two States can be converted (from pending ---> fulfilled, pending-> rejected), and only one State can be converted.
1.4.2 then Method
The then method is used to specify the callback function after the asynchronous event is completed.
This method can be said to be the soul method of Promise, which makes Promise full of magic. There are several specific manifestations:
A) The then method returns Promise. In this way, serial operations of multiple asynchronous operations are implemented.
The processing of value in the middle yellow circle 1 is a complicated area in Promise. The processing of value is divided into two situations: Promise object and non-Promise object.
When the value is not of the Promise type, the value is directly used as the resolve parameter value of the second Promise. When the value is of the Promise type, the status and parameters of promise2 are completely determined by the value, it can be considered that promsie2 is the dumb of value, and promise2 is only a bridge connecting different asynchronous methods.
The Code is as follows:
Promise. prototype. then = function (onFulfilled, onRejected ){
Return new Promise (function (resolve, reject) {// The Promise here is marked as promise2
Handle ({
OnFulfilled: onFulfilled,
OnRejected: onRejected,
Resolve: resolve,
Reject: reject
})
});
}
Function handle (deferred ){
Var handleFn;
If (state = 'fullfiled '){
HandleFn = deferred. onFulfilled;
} Else if (state = 'objected '){
HandleFn = deferred. onRejected;
}
Var ret = handleFn (value );
Deferred. resolve (ret); // note that the resolve is the resolve of promise2.
}
Function resolve (val ){
If (val & typeof val. then = 'function '){
Val. then (resolve); // if val is a promise object or a promise-like object, the state of promise2 is completely determined by val.
Return;
}
If (callback) {// callback is the specified callback function
Callback (val );
}
}
B) converts multiple asynchronous libraries.
In asynchronous mode, a thenable object is an object with a then method. If an object has a then method, it can be converted. For example:
The Code is as follows:
Var deferred = $ ('aa. ajax ');//!! Deferred. then = true
Var P = Promise. resolve (deferred );
P. then (......)
1.4.3 commonJS Promise/A Specification
Currently, Promise specifications include Promise/A and Promise/A + specifications. This shows that the implementation of Promise is quite complicated.
The Code is as follows:
Then (fulfilledHandler, rejectedHandler, progressHandler)
1.4.4 notes
The callback function in a Promise shares the value. In result processing, the value is passed as a parameter to the corresponding callback function. If the value is an object, be careful not to modify the value easily.
The Code is as follows:
Var p = Promise. resolve ({x: 1 });
P. then (function (val ){
Console. log ('first callback: '+ val. x ++ );
});
P. then (function (val ){
Console. log ('second callback: '+ val. x)
})
// First callback: 1
// Second callback: 2
1.5 Generator
All the above methods are based on callback functions to complete asynchronous operations. They are nothing more than encapsulation of callback functions. In ES6, Generator is proposed, which increases the way to solve asynchronous operations and is no longer completed based on the callback function.
The biggest feature of Generator is that it can pause and restart functions. This feature is very helpful for asynchronous operations. Combining the pause of Generator with the exception handling of promise can solve asynchronous programming problems elegantly. For more information, see Kyle Simpson.
2. Problems in asynchronous programming
2.1 Exception Handling
A) asynchronous events include two links: sending asynchronous requests and processing results. These two links are connected through event loop. Then try catch to capture exceptions.
The Code is as follows:
Try {
AsyncEvent (callback );
} Catch (err ){
......
}
The above Code cannot catch exceptions in callback, and can only get exceptions in the process of sending requests. In this way, there is a problem: if the request is sent and the request is handled by two people, then there is a problem in the Exception Processing?
B) promise implements exception transfer, which brings some benefits and ensures that the Code is not blocked in the actual project. However, when there are many asynchronous events, it is difficult to find out whether the asynchronous event generates an exception.
The Code is as follows:
// Scenario Description: The price alarm information is displayed in CRM, which contains the competing information. However, it takes a long time for the backend to obtain the information of a competitor. To avoid slow queries, the backend Splits a record into two parts to obtain the information respectively.
// Step 1: Get price alarm information, except for competing information
Function getPriceAlarmData (){
Return new Promise (function (resolve ){
Y. io (url ,{
Method: 'get ',
Data: params,
On: function (){
Success: function (id, data ){
Resolve (alarmData );
}
}
});
});
}
// After obtaining the alarm information, obtain the competitor Information
GetPriceAlarmData (). then (function (data ){
// Data Rendering, except for competing information
Render (data );
Return new Promise (function (resolve ){
Y. io (url ,{
Method: 'get ',
Data: {alarmList: data },
On: function (){
Success: function (id, compData ){
Resolve (compData );
}
}
});
});
}) // After obtaining all the data, the game renders the information.
. Then (function (data ){
// Render competing information
Render (data)
}, Function (err ){
// Exception Handling
Console. log (err );
});
You can convert the above Code into the following:
The Code is as follows:
Try {
// Obtain the alarm information except the competing pair
Var alarmData = alarmdata‑tcompare ();
Render (alarmData );
// Query the competitor information based on the alarm information
Var compareData = getCompareInfo (alarmData );
Render (compareData );
} Catche (err ){
Console. log (err. message );
}
In the above example, we put exception processing at the end of the process. In this way, when an exception occurs in a link, we cannot know exactly which event was generated.
2.2 jQuery. Deferred Problems
JQuery also implements asynchronous operations, but the implementation does not comply with the promise/A + specification, mainly in the following aspects:
A. Number of parameters: the standard Promise can only accept one parameter, while jQuery can pass multiple parameters.
The Code is as follows:
Function asyncInJQuery (){
Var d = new $. Deferred ();
SetTimeout (function (){
D. resolve (1, 2 );
},100 );
Return d. promise ()
}
AsyncInJQuery (). then (function (val1, val2 ){
Console. log ('output: ', val1, val2 );
});
// Output: 1 2
B. Handling of exceptions in result Processing
The Code is as follows:
Function asyncInPromise (){
Return new Promise (function (resolve ){
SetTimeout (function (){
Var jsonStr = '{"name": "mt }';
Resolve (jsonStr );
},100 );
});
}
AsyncInPromise (). then (function (val ){
Var d = JSON. parse (val );
Console. log (d. name );
}). Then (null, function (err ){
Console. log ('show error: '+ err. message );
});
// Show error: Unexpected end of input
Function asyncInJQuery (){
Var d = new $. Deferred ();
SetTimeout (function (){
Var jsonStr = '{"name": "mt }';
D. resolve (jsonStr );
},100 );
Return d. promise ()
}
AsyncInJQuery (). then (function (val ){
Var d = JSON. parse (val );
Console. log (d. name );
}). Then (function (v ){
Console. log ('success: ', v. name );
}, Function (err ){
Console. log ('show error: '+ err. message );
});
// Uncaught SyntaxError: Unexpected end of input
As you can see, Promise processes the result of the callback function, which can capture exceptions during the execution of the callback function, but jQuery. Deferred cannot.