async.js 原理解析
暂时只是针对常用的Waterfall方法
做node开发,你不能逃避的一个组件:async.js. 神奇之处在于让你用看上去同步的方式写出异步的代码,把我们从各种回调嵌套中解脱出来,程序逻辑一目了然.以下简要对async的each和waterfall方法的实现原理做介绍.
async.each
先看使用方法
async.waterfall([
function(callback){ callback(null, ‘one‘, ‘two‘); }, function(arg1, arg2, callback){ // arg1 now equals ‘one‘ and arg2 now equals ‘two‘ callback(null, ‘three‘); }, function(arg1, callback){ // arg1 now equals ‘three‘ callback(null, ‘done‘); }], function (err,
result) { // result now equals ‘done‘
});
来自官方的例子,waterfall函数接受2个参数,第一个是函数数组,第二个市回调函数.waterfall方法可以让函数数组逐次执行,执行完毕或出现错误的时候,执行最后的回调函数.
关键在于函数数组中额外添加callback这个传入的参数,最开始我以为async维护了一个队列,当我们在函数体内部调用callback的时候,回到async的执行,然后有async去执行下一个函数.事实并不是这样的...
先一句话解释一下整个原理,后面再说明:
把下一个要执行的函数包装在一个函数体中,以callback的方式传入当前执行的函数,当我们显式执行callback()的时候其实调用了下一个函数
我们来看看waterfall的实现:
async.waterfall = function (tasks, callback) {
callback = callback || function () {}; if (!_isArray(tasks)) { var err = new Error(‘First argument to waterfall must be an array of functions‘); return callback(err); } if (!tasks.length) { return callback(); } var wrapIterator = function (iterator) { return
function (err) { if (err) { callback.apply(null, arguments); callback = function () {}; } else { var args = Array.prototype.slice.call(arguments, 1); var next = iterator.next(); if (next) { args.push(wrapIterator(next)); } else { args.push(callback); } async.setImmediate(function
() { iterator.apply(null, args); }); } }; }; wrapIterator(async.iterator(tasks))(); };
逐行解释一下:
首先是定义了一个wrap函数
var wrapIterator = function (iterator){}
然后调用wrapIterator(),async.iterator是返回这样的一个对象
fn: 当前执行的函数 fn.next: 返回下一个iterator的匿名函数
以官方例子的第二个function来说明:
* 首先判断一下有没有err,如果有,直接执行到最后的回调函数
* 把err slice掉,剩下的是传递到下一个函数的参数[‘one‘, ‘two‘]
* 从iterator中取到下一个函数放到参数列表的最后一个,如果没有,放入最后的回调函数[‘one‘, ‘two‘, wrap(function(arg1, callback){})]
* 调用当前要执行的函数,传入的参数,即执行 function(arg1=>‘one‘,arg2=>‘two‘,callback=>‘wrap*****‘){
}
剩下的事情我们就都知道了.
有点啰嗦,不知道说清楚了没有,o(╯□╰)o