waterfall和series函数都是按照顺序执行,不同之处是waterfall每个函数产生的值都可以传递给下一个函数,series不可以。
实现
// util.js
module.exports = {
noop() { },
restArgs: function (fn, startIdx) {
// fn为传进来的的函数
startIdx = startIdx == null ? fn.length - 1 : +startIdx;
return function () {
let len = Math.max(arguments.length - startIdx, 0),
rest = new Array(len),
i;
for (i = 0; i < len; i++)
rest[i] = arguments[i + startIdx];
switch (startIdx) {
case 0: return fn.call(this, rest);
case 1: return fn.call(this, arguments[0], rest);
case 2: return fn.call(this, arguments[0], arguments[1], rest);
}
let args = new Array(startIdx + 1);
for(i=0;i<startIdx;i++)
args[i] = arguments[i];
args[startIdx] = rest;
return fn.apply(this,args);
}
},
waterfall: function (tasks, cb) {
let self = this;
cb = cb || noop;
let current = 0;
// taskCb是restArgs返回的匿名函数
let taskCb = this.restArgs(function (err, args) {
if (++current >= tasks.length || err) {
args.unshift(err);
process.nextTick(function () { cb.apply(null, args); cb = self.noop })
} else {
args.push(taskCb);
tasks[current].apply(null, args)
}
})
if (tasks.length) {
// 此处的taskCb其实就是test.js里每个function里的cb()
tasks[0](taskCb)
} else {
process.nextTick(function () { cb(null); cb = this.noop })
}
}
}
测试文件
//test
const util = require('./util')
util.waterfall([
function(cb){
setTimeout(()=>{
cb(null, 'one','two','three','four')
},1000);
},
function(args1,args2,args3,args4,cb){
// args1 -> 'one'
console.log(args1)
console.log(args2)
console.log(args3)
console.log(args4)
cb(null, 'done')
}
],function(err, result){
// result -> 'done'
console.log(result)
})