什么是async.waterfall的简单实现?

我正在使用asynchronous库中的一些函数,并且要确保我理解他们在内部是如何做的。 然而,我卡在async.waterfall ( 这里的实现 )。 实际的实现使用了库内的其他function,没有太多的经验,我觉得很难遵循。

有人可以不担心优化,提供一个非常简单的实现,实现瀑布的function? 大概是这个答案可比的东西。

从文档中 ,瀑布的描述:

按顺序运行函数的任务数组,每个函数将结果传递给数组中的下一个。 但是,如果任何任务将错误传递给自己的callback,则不执行下一个函数,并立即调用主callback并返回错误。

一个例子:

 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' }); 

那么,这是一个简单的实现通过排队他们链接function。

首先,function:

 function waterfall(arr, cb){} // takes an array and a callback on completion 

现在,我们需要跟踪数组并重复它:

 function waterfall(arr, cb){ var fns = arr.slice(); // make a copy } 

让我们开始处理传递和空的数组,通过添加一个额外的参数,所以我们可以传递结果称为result

 function waterfall(arr, cb, result){ // result is the initial result var fns = arr.slice(); // make a copy if(fns.length === 0){ process.nextTick(function(){ // don't cause race conditions cb(null, result); // we're done, nothing more to do }); } } 

这很好:

 waterfall([], function(err, data){ console.log("Done!"); }); 

现在,我们来处理实际的东西:

 function waterfall(arr, cb, result){ // result is the initial result var fns = arr.slice(1); // make a copy, apart from the first element if(!arr[0]){ // if there is nothing in the first position process.nextTick(function(){ // don't cause race conditions cb(null, result); // we're done, nothing more to do }); return; } var first = arr[0]; // get the first function first(function(err, data){ // invoke it // when it is done if(err) return cb(err); // early error, terminate entire call // perform the same call, but without the first function // and with its result as the result waterfall(fns, cb, data); }); } 

而就是这样! 我们克服了基本上使用recursion无法循环callback的事实。 这是一个小提琴说明。

值得一提的是,如果我们用承诺实现它,我们可以使用for循环。

对于那些想保持简短的人:

 function waterfall(fn, done){ fn.length ? fn.shift()(function(err){ err ? done(err) : waterfall(fn, done) }) : done(); }