What is a simple implementation of async.waterfall?
我正在使用异步库中的某些函数,并希望确保我了解它们在内部的工作方式;但是,我被困在
有人可以在不担心优化的情况下提供实现瀑布功能的非常简单的实现吗?可能与该答案具有可比性。
从文档中,瀑布的描述:
Runs the tasks array of functions in series, each passing their
results to the next in the array. However, if any of the tasks pass an
error to their own callback, the next function is not executed, and
the main callback is immediately called with the error.
一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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' }); |
好吧,这是通过对函数进行排队来链接函数的简单实现。
首先,函数:
1 | function waterfall(arr, cb){} // takes an array and a callback on completion |
现在,我们需要跟踪数组并对其进行迭代:
1 2 3 | function waterfall(arr, cb){ var fns = arr.slice(); // make a copy } |
让我们开始处理传递的数组和空数组,方法是添加一个额外的参数,以便我们可以将结果传递给
1 2 3 4 5 6 7 8 | 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 }); } } |
这很好:
1 2 3 | waterfall([], function(err, data){ console.log("Done!"); }); |
现在,让我们处理一下其中的东西:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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); }); } |
就是这样!通过基本使用递归,我们克服了无法循环使用回调的事实。这是一个说明性的小提琴。
值得一提的是,如果使用promise实现它,我们可能会使用for循环。
对于那些喜欢简短的人:
1 2 3 | function waterfall(fn, done){ fn.length ? fn.shift()(function(err){ err ? done(err) : waterfall(fn, done) }) : done(); } |