Node.JS 中的一大麻烦就是异步函数太多,导致程序的流程不好控制。但是,有了 async 模块,这个问题不再是问题了。这里我们总结下 async 模块的用法。
假如我们需要分别读取两个文件的内容,如果两者都成功就执行其它操作。如果按照同步的思路,代码如下:
function task1() { fs.readFile('somefile', function(err, data) { if (err) throw err; window.data1 = data; console.log('task1 done!'); }); } function task2() { fs.readFile('morefile', function(err, data) { if (err) throw err; window.data2 = data; console.log('task2 done!'); }); } function then() { var data1 = window.data1; var data2 = windos.data2; console.log(data1 + data2); console.log('both tasks done!'); } task1(); task2(); then();
但是现在 readFile 是异步函数,这样的代码是错误的:因为它将导致函数 then 的结果先输出。要改为正确的写法需要函数的嵌套,很繁琐也难看。现在改为 async 模块的写法就简单多了:
async.parallel([ function(callback){ fs.readFile('somefile', function(err, data) { console.log('task1 done!'); callback(err, data); }); }, function(callback){ fs.readFile('morefile', function(err, data) { console.log('task2 done!'); callback(err, data); }); } ], function(err, results){ if (err) throw err; var data1 = results[0]; var data2 = results[1]; console.log(data1 + data2); console.log('two tasks done!'); });
这里用到 async 的 parallel 这个同步执行的函数,它保证前面的两个函数都执行完毕后才执行原来函数 then 的内容。另外你会注意到这种用法的关键之处:并行执行的每个函数都必须有 callback 参数,这个 callback 参数负责在该函数最后提供出错信息和返回值给 parallel 函数。因此,这个 callback 函数一定要调用它,即使没有出错信息和返回值也应该在最后用 callback()。
如果前面两个任务的 console.log 不需要,上面的代码还可以简化如下:
async.parallel([ function(callback){ fs.readFile('somefile', callback); }, function(callback){ fs.readFile('morefile', callback); } ], function(err, results){ if (err) throw err; var data1 = results[0]; var data2 = results[1]; console.log(data1 + data2); console.log('two tasks done!'); });
这是因为 async 任务的回调函数和 Node.JS 异步操作的回调函数参数是一致的:都是 error 和 data 这两个。这样写起来就更加简洁漂亮了。
async 还有更多的函数,比如 series,waterfall,auto,each 等等其它控制异步执行流程的函数,它们的用法和上面的例子类似。
参考资料:
[1] caolan/async - Async utilities for node and the browser
[2] Node.js async in practice: When to use what?
[3] Async详解之一:流程控制 | Freewind.me
[4] Async详解之二:工具类 | Freewind.me
[5] Async详解之三:集合操作 | Freewind.me
[6] node.js async.series not working - Stack Overflow
[7] Asynchronous code in node.js