In JS or node programming, due to the frequent and extensive use of asynchronous, so that the callback and nesting depth caused by the experience of programming encountered some challenges, if you write elegant and good-looking code, this article mainly for asynchronous programming mainstream program to do some summary
1. Event Publish/Subscribe mode
Event Listener mode is a widely used mode for asynchronous programming, is the event of callback function, also known as the Publish/Subscribe mode, node itself provides the events module, is a simple implementation of the pattern.
Eventporxy
2. PROMISE/DEFERRD mode
In 2009, Kris Zyp was abstracted as a draft proposal, published in the COMMONJS specification, and currently, the COMMONJS draft includes PROMISE/A, Promise/b, and promise/d asynchronous models. Because the promise/a is more commonly used is also relatively simple, only need to have then () method. So first introduce some of the change mode.
In general, the then () method is defined as follows:
Then (Fulfilledhandler, ErrorHandler, Progresshandler)
promises/a
By inheriting node's events module, we can implement a simple promise module.
Promise part
var Promise = function () { eventemitter.call (this);} Util.inherits (Promise, Eventemitter); Util is the tool class with node Promise.prototype.then = function (Fulfilledhandler, ErrorHandler, Progresshandler) { if (typeof Fulfilledhandler = = = "function") { this.once (' success ', Fulfilledhandler); } if (typeof ErrorHandler = = = "function") { this.once (' Error ', ErrorHandler); } if (typeof Progresshandler = = = "function") { This.on (' Progress ', Progresshandler); }
Deferred part
var Deferred = function () { this.state = ' unfulfilled '; This.promise = new Promise ();} Deferred.prototype.resolve = function (obj) { this.state = ' fulfilled '; This.promise.emit (' success ', obj);} Deferred.prototype.reject = function (obj) { this.state = ' failed '; This.promise.emit (' error ', obj);} Deferred.prototype.progress = function (obj) { this.promise.emit (' Progress ', obj);}
Use
function readFile (file, encoding) { var deferred = new deferred (); Fs.readfile (file, encoding, deferred.resolve); return deferred.promise;} ReadFile ('/test.txt ', ' Utf-8 '). Then (function (data) { ...}, function (err) { ...});
The above is a simple implementation of the promise/deferred pattern, which can be described in the state transition diagram:
The promise mode is slightly more elegant than the Publish/subscribe model, but it does not meet the real needs of many scenarios, such as a set of purely asynchronous APIs to work together to complete a string of things.
promises/a+
The specification clarifies the recommendations of the previous PROMISES/A specification for the standard of conduct. It extends the original specification to cover some of the customary behavior, and omits some parts that exist only in certain situations or that have problems.
See: Chinese version: http://www.ituring.com.cn/article/66566, English version: https://promisesaplus.com/
3. Process Control repository tail trigger and next
Tail trigger is currently the most widely used in the middleware of Connect, middleware processing network requests, can be used for cutting-oriented programming, such as filtering, verification, logging and other functions, the simplest middleware is as follows:
Function (req, res, next) { //middleware }
Each middleware passes the request object, the response object, and the tail trigger function, forming a processing stream through the queue as follows:
See an example
App.use (function (req, res, next) { setTimeout (function () { next (); }, 0)}, function (req, res, next) { SetTimeout (function () { next (); }, 0);});
From this example, we can easily guess the implementation principle of the tail trigger, simply by invoking use to maintain a queue, call next when the team out and execute, loop in turn.
Async
Currently the most well-known Process Control module, Async module provides more than 20 methods for handling asynchronous multiple writing modes, such as:
1. Asynchronous Serial execution
Async.series ([ function (callback) { //do some stuff ... Callback (NULL, ' one '); }, function (callback) { //do some more stuff ... Callback (NULL, ' both '); }],//Optional callbackfunction (err, results) { //results is now equal to [' One ', ' both ']}) ;
An example using a object instead of an arrayAsync.Series({One:function(Callback){SetTimeout(function(){Callback(Null,1); 200}, twofunction ( callback) {settimeout ( Function () {callback (null2); 100}},function (err results) {//results Equal to: {one:1, Two:2}
The exception handling principle is the first parameter that encounters an exception that ends all calls and passes an exception to the final callback function
2. Asynchronous Parallel execution
An example using a object instead of an arrayasync.parallel ({ one:function (callback) { setTimeout (function () { callback (null, 1); }, two:function (callback) { setTimeout (function () { callback (null, 2); }, }},function (err, results) { //results is today equals to: {one:1, two:2}});
Unlike Eventproxy-based event publishing and subscription patterns, which are used by callback functions, async callback functions are passed in by async, and Eventproxy uses the Done (), fail () method to generate a new callback function, which is the application of higher-order functions.
3. Dependency processing of asynchronous calls
Async.waterfall ([ function (callback) { callback (null, ' One ', ' both ') , function (arg1, arg2, Callback) { //arg1 now equals ' one ' and arg2 now equals ' both ' callback (NULL, ' three '); }, function (Arg1, Callback) { //arg1 now equals ' three ' callback (null, ' done '); }], function (err, result) { //Result No W equals ' Done ' });
4. Automatic Dependency processing
Async.auto ({get_data:function (callback) {Console.log (' in Get_data '); Async code to get some data callback (NULL, ' data ', ' converted to array '); }, Make_folder:function (callback) {Console.log (' in Make_folder '); Async code to create a directory to store a file in//This is run at the same time as getting the data C Allback (null, ' folder '); }, Write_file: [' get_data ', ' Make_folder ', function (callback, results) {Console.log (' in Write_file ', json.string Ify (results)); Once there is some data and the directory exists,//write the data to a file in the directory callback (n ull, ' filename '); }], Email_link: [' Write_file ', function (callback, results) {Console.log (' in Email_link ', json.stringify (results) ); Once the file is written let's email a link to it ...//Results.write_file contains the filename returned by WRI Te_file. Callback (NULL, {' file ': Results.wriTe_file, ' email ': ' [email protected] '}); }]}, function (err, results) {console.log (' err = ', err); Console.log (' results = ', results);});
In a real-world business environment, there are many complex dependencies, and synchronization and asynchrony are not deterministic, so the auto method can automatically analyze execution based on dependencies.
Step
The lightweight async is also consistent with API exposure because there is only one interface step.
There are some differences in asynchronous processing, and once the step produces an exception, it will be passed in as the first parameter of the next method.
var s = require (' step '); s ( function readself () { fs.readfile (__filename, this); }, function (err, Content) { //Parallel execution of task Fs.readfile (__filename, This.parallel ()); Fs.readfile (__filename, This.parallel ()); }, function () {
Task group Save result var group = This.group (); Console.log (arguments); Fs.readfile (__filename, Group ()); Fs.readfile (__filename, Group ()); }, function () { console.log (arguments); } )
Wind
Pending additions
Summarize
Compare the differences between several scenarios: the event Publish/Subscribe mode is relatively primitive, and the promise/deferred model contributes a very good abstraction of the asynchronous task model, starting with encapsulating the asynchronous invocation part, while the Process Control library is much more flexible.
In addition to async, step, Eventproxy, wind and other programs, there is a class of source code compiled by the scheme to achieve the simplification of the process control, streamline is a typical example.
Reference
The fourth chapter of the Nodejs in layman's
https://promisesaplus.com/
https://github.com/caolan/async/
Https://github.com/creationix/step
http://www.ituring.com.cn/article/66566
Nodejs Learning Notes-Asynchronous programming solutions