Objective
The biggest highlight of Nodejs is the event-driven, non-blocking I/O model, which makes Nodejs highly capable of concurrency and is ideal for writing network applications. Most of the I/O operations in Nodejs are almost asynchronous, that is, the results of the operations we handle I/O basically need to be handled in the callback function, such as the following function to read the contents of the file:
function (err, data) { ifthrow err; Console.log (data);});
So, what do we do when we read two files and merge the contents of these two files together? Most people who touch JS soon may do this:
function (err, data) { ifthrow err; Fs.readfile (function (err, data2) { ifthrow err; // data and data2 are processed here });});
If you deal with a number of similar scenarios, it is not a layer of callback function nested Ah, this is what we often call the callback pyramid or callback Hell (http://callbackhell.com/) problem, but also let JS small white most headache problem.
This layer of nested code has brought a lot of problems to development, mainly reflected in:
- Bad code possibilities
- Difficult to debug
- Difficult to troubleshoot when an exception occurs
This article is mainly about how to gracefully handle the above asynchronous callback problem.
Primary scenario: Asynchronous callbacks are processed by recursion
We can use recursion as the execution Control tool for the code. Wrap the action that needs to be performed into a function, in the callback function through recursive call control code execution flow, nonsense, the last code:
varFS = require (' FS ');//list of files to processvarFiles = [' File1 ', ' file2 ', ' file3 '];functionParsefile () {if(Files.length = = 0) { return; } varFile =Files.shift (); Fs.readfile (file,function(err, data) {//file data is processed hereParsefile ();//after processing, the next file is processed by a recursive call });}//Start processingParsefile ();
The above code, in turn, processes the files in the array as an example, and describes how to control the execution of the code recursively.
It's good to apply it to a few simple scenarios, such as: we can do this by saving the data in an array to the database in turn.
Some simple asynchronous callback problems can be solved by recursive method. However, it is still somewhat powerless to handle complex asynchronous callbacks, such as the need to synchronize the results of multiple asynchronous operations.
Gorgeous point: Handling asynchronous callbacks with third-party libraries such as Async, Q, Promise
To better handle the problem of nested callbacks, consider using some third-party specialized to handle the asynchronous library, of course, the ability to write an asynchronous processing of the auxiliary tools.
The more commonly used libraries for handling asynchrony are: async,q and promise. From the npmjs.org website, async is the most fiery. Previously used async, it is also very convenient, a variety of asynchronous processing control flow implementation is also very good.
We will initially read two files at the same time using async processing code, the example below:
varAsync = require (' async '), FS= Require (' FS '); Async.Parallel ([function(callback) {Fs.readfile ('/etc/passwd ',function(err, data) {if(ERR) callback (ERR); Callback (NULL, data); }); }, function(callback) {Fs.readfile ('/etc/passwd2 ',function(Err, data2) {if(ERR) callback (ERR); Callback (NULL, data2); }); }],function(err, results) {//data and data2 are processed here, and the contents of each file are retrieved from the results});
Through the Async module, you can control the asynchronous execution process, but also to solve the problem of layer callback, the code is clearer than before, but still inseparable from the callback function.
Think it would be nice to be able to handle asynchrony without using a callback function, and then we'll talk about using the new features of ES6 to achieve this goal.
Elegant point: Hug ES6, replace callback function, solve callback hell problem
Say ECMAScript Harmony (ES6) to JS introduced a lot of new features, ES6 not too understand the classmate, can self-Baidu a bit.
Using the new features of ES6 in Nodejs, you need to use more than v0.11.x versions.
This article describes the use of the generator attribute instead of a callback function, which is not known to generator? can look here.
There are two modules for CO and thunkify, which are installed using the NPM Install command.
As an example, the example code for using the generator attribute is as follows:
var fs = require (' FS ') = require ( ' co ') = require (' thunkify '); var readFile = thunkify (fs.readfile), CO (function *() { var test1 = Yield ReadFile (' test1.txt '); var test2 = yield readFile (' test2.txt '); var test = test1.tostring () + test2.tostring (); Console.log (test);}) ();
It's easy to handle exceptions in your code, just so it's OK:
Try { var test1 = yield readFile (' test1.txt 'catch (e) { // handle exceptions here }
Is this code a lot more elegant? It's cool to deal with asynchrony like writing synchronous code!
Nodejs in the field of web development, the most fire frame is express, it is worth mentioning that the core member of the Express TJ God has led a new web framework--koa, claiming to be the next generation of web development framework, KOA is really using the ES6 generator feature, so that we avoid falling into layers of callback when developing a web system.
Summarize
Quote the FIBJS project propaganda sentence: Less Callback, more Girls-fewer callbacks, more sister
Resources
http://blog.nodejs.org/2014/03/12/node-v0-11-12-unstable/
http://huangj.in/765
http://tobyho.com/2013/06/16/what-are-generators/
http://blog.shiqichan.com/using-es6-generators-in-nodejs/
http://www.html-js.com/article/1687
http://www.ituring.com.cn/article/62609
How to gracefully handle asynchronous callbacks in Nodejs