NodeJS异步调用的顺序化处理
NodeJS本身一个重要的特性就是异步处理,但异步处理多了,会把一个完整的“业务”逻辑拆分的支离破碎,让人看到头大,或许这就是所谓的异步陷阱?!最近看NodeJS项目代码时,发现了一个Step的模块,就是专门将一系列执行有先后关系的异步调用做序列化调用处理的,使之在代码层面上尽量看起来更清晰。Step详情可参见 https://github.com/creationix/step
1. 简单的将异步处理顺序化
step本身定义了一个 Step 的方法, Step可以接收任意多的方法,并按顺序执行这些方法,其中this代表下一个方法的回调。
var fs = require('fs');
var Step = require('step');
Step( function readSelf() {
fs.readFile(__filename, 'utf-8', this); },
function capitalize(err, text) {
if (err) throw err;
return text.toUpperCase();
},
function showIt(err, newText) {
if (err) throw err;
console.log(newText);
}
);
执行以上代码后,会看到一段大写的代码,从代码逻辑上不难理解:
- readSelf(), 使用了异步函数读取方法readFile(), 并通过this来指定下一个方法(capitalize)作为callback函数。
- capitalize(), 没有使用异步方法,所以直接通过return调用下一个方法(showIt)
- showIt(), 将上一个方法return的值(newText)打印出来
第一个参数固定为一个异常接收的参数,只要你不嵌套回调,这将有助于你捕获所有的异常,保证你的服务足够健壮。
2. 通过this.parallel()实现并行调用
如果在一个逻辑处理,我们需要触发多个异步调用,并写保证这个逻辑的顺序执行,我们可以使用this.parallel() 来代替 this,通过代码我们将很容易明白:
var fs = require('fs');
var Step = require('step');
Step( // Loads two files in parallel
function loadStuff() {
fs.readFile(__filename, 'utf-8', this.parallel());
fs.readFile("/etc/passwd", 'utf-8', this.parallel());
},
// Show the result when done function
showStuff(err, code, users) {
if (err) throw err;
console.log(code);
console.log(users);
}
)
3. group() 方法
如果在一个方法内,我们需要批量调用同一个回调方法,并对该方法产生的数据有统一的处理模式,那么我们需要使用group()。例如我们需要读取一个目录下所有的js文件,然后再将这些文件的内容打印出来,我们就可以使用group这个方法。看代码会比较好明白:
var fs = require('fs');
var Step = require('step');
Step(
function readDir() { fs.readdir(__dirname, this); },
function readFiles(err, results) {
if (err) throw err; // Create a new group
var group = this.group();
results.forEach(function (filename) {
if (/\.js$/.test(filename)) {
fs.readFile(__dirname + "/" + filename, 'utf8', group()); } }); },
function showAll(err , files) {
if (err) throw err;
console.dir(files);
}
);
其中特别需要说明的是,这里的group()一定要“new”出来一个,不可直接使用this.group(),因为此处的group()需要统一管理所有回调的状态,也就是说在 readFiles().results.forEach循环回调读取当前目录下所有文件完成后,再统一调用下一步定义的文件内容处理方法showAll()。