Foreword
The biggest highlight of Nodejs is the event-driven, non-blocking I/O model, which makes Nodejs have strong concurrent processing capabilities and is very suitable for writing network applications. Most I/O operations in Nodejs are almost asynchronous, that is, the results of our I/O operations basically need to be processed in callback functions, such as the following function that reads file content:
Then, what should we do if we read two files and merge the contents of the two files together for processing? Most people who have been exposed to js for a short time may do this:
If you deal with multiple similar scenarios, wouldn’t it be that the callback functions are nested layer by layer? This is what everyone often calls the callback pyramid or callback hell (http://callbackhell.com/) is also the most troublesome problem for js newbies.
This kind of nested code brings many problems to development, mainly reflected in:
1. Code possibility becomes worse
2. Difficulty in debugging
3. Difficult to troubleshoot when an abnormality occurs
This article mainly introduces how to handle the above asynchronous callback issues gracefully.
Basic solution: Handle asynchronous callbacks recursively
We can use recursion as an execution control tool for our code. Encapsulate the operations that need to be performed into a function, and control the execution process of the code through recursive calls in the callback function. Without further ado, let’s go to the last code:
function parseFile () {
if (files.length == 0) {
Return;
}
var file = files.shift();
fs.readFile(file, function (err, data) {
// File data is processed here
ParseFile(); // After processing, process the next file through recursive call
});
}
//Start processing
parseFile();
The above code has processed the files in the array sequentially as an example, introducing the recursive method to control the execution flow of the code.
It is good to apply it to some simple scenarios. For example, we can use this method to save the data in an array to the database in sequence.
Some simple asynchronous callback problems can be solved through recursion. However, it is still somewhat incapable of handling complex asynchronous callbacks (such as the need to synchronize the results of multiple asynchronous operations).
Gorgeous point: Use third-party libraries such as Async, Q, and Promise to handle asynchronous callbacks
In order to better handle the problem of nested callbacks, you can consider using some third-party libraries that specialize in asynchronous processing. Of course, if you have the ability, you can write your own auxiliary tool for asynchronous processing.
The more commonly used libraries for handling asynchronous processing are: async, q and promise. Judging from the npmjs.org website, async is the most popular. I have used async before, and it is indeed very convenient. The control flow of various asynchronous processing is also implemented very well.
We will use async to process the initial code that reads two files at the same time. The example is as follows:
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){
// The data of data and data2 are processed here, and the content of each file is obtained from results
});
Through the async module, the asynchronous execution process can be well controlled, which can also be regarded as solving the problem of callbacks at all levels. The code is clearer than before, but it is still inseparable from the callback function.
Think about it, wouldn’t it be great if you could handle asynchronous processing without using callback functions? Next, let’s talk about using the new features of ES6 to achieve this goal.
Be elegant: embrace ES6, replace callback functions, and solve the callback hell problem
It is said that EcmaScript Harmony (ES6) has introduced many new features to js. Students who don’t know much about ES6 can check it out on Baidu.
To use the new features of ES6 in nodejs, you need to use version v0.11.x or above.
This article introduces the use of Generator features to replace callback functions. Don’t you know about Generator? You can take a look here.
The two modules co and thunkify are used here. You can install them using the npm install command.
Let’s take the problem mentioned at the beginning of this article as an example. The example code for using the generator feature is as follows:
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);
})();
Handling exceptions in code is also very simple, just do this:
Isn’t this code much more elegant? Isn’t it great to handle asynchronous code just like writing synchronous code?
For web development in the field of nodejs, the most popular framework is express. It is worth mentioning that TJ, a core member of express, has led a new web framework-koa, which is claimed to be the next generation web development framework. , koa really takes advantage of the generator feature of ES6, allowing us to avoid falling into layers of callbacks when developing web systems.
Summary
Quoting a sentence from the fibjs project promotion: Less Callback, More Girls - Less callback, more girls