Node.js 中 For 循环中的 async.waterfall

Posted

技术标签:

【中文标题】Node.js 中 For 循环中的 async.waterfall【英文标题】:async.waterfall in a For Loop in Node.js 【发布时间】:2015-10-26 06:16:40 【问题描述】:

for 循环中使用async.waterfall 时,for 循环似乎在嵌套的async.waterfall 完成其所有步骤之前迭代。如何避免这种情况?

for(var i = 0; i < users.length; i++ ) 

    console.log(i)

    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'
        console.log('done')
    );



输出

0
1
2
3
4
done
done
done
done
done

期望的输出

0
done
1
done
2
done
3
done
4
done

【问题讨论】:

for-loop 是一个同步工作块,它在 eventloop 队列上发布异步工作——那么为什么它需要以不同的顺序工作呢?也许澄清你的实际问题会给你一个更好的答案。 不要使用for 循环,而是使用async.map(或任何你需要的) 【参考方案1】:

您需要应用递归模式。我的建议是这样的

function foo(properties, callback)
/*Initialize inputs w/ useful defaults.  Using a properties object simply because it looks nicer, you can use individual values if you'd like.*/
        properties.start = properties.start || 0;
        properties.end = properties.end || 10; //or any default length
        properties.data = properties.data || [];

        async.waterfall([
          function(callback) 
        ,
        function(arg1, arg2, callback) 
          /* arg1 now equals 'one' and arg2 now equals 'two' you can do something with that before continuing processing */
        ,
        function(arg1, callback) 
            /* arg1 now equals 'three', you can do something with that before continuing processing */

        
    ], function (err, result) 
        // result now equals 'done' 
        // now that we have fully processed one record, we need to either finish or recurse to the next element.  

     if(properties.index >= properties.end)
       callback();
     
     else
       properties.index++;
       foo(properties, callback);
     

    )

我已将回调传递给每个函数回调。如果你愿意,你可以选择以这种方式提前结束递归,或者你可以在那个地方做任何你想做的事情。这类似于我最近提出的一个问题:Patterns for asynchronous but sequential requests,它也有一些其他有趣的解决方案。

【讨论】:

async 库已经可用时,为什么要使用递归? 个人喜好。如果异步库在语言级别上进行了优化,它实际上可能性能更高(这个例子效率很低,但我想说明递归的概念而不是想炫耀我的能力)。还没有真正深入研究过那个库中的代码,我很难说。 我怀疑 async.js 的性能会更好,而且库代码确实很糟糕,但使用它的代码会更具可读性。 我不知道更具可读性,这只是一个调用来执行遍历数组的任务。也就是说,开发人员有责任维护这一点并在未来的任何变化中看到它。这绝对是使用异步库的充分理由。 TBH,我不知道异步库可以在这样的数据结构级别上做到这一点。正如我之前提到的,我还没有花时间学习它。【参考方案2】:

你可以像这样使用 async 的 forEachLimit

var async = require("async")
var users = []; // Initialize user array or get it from DB

async.forEachLimit(users, 1, function(user, userCallback)

    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'
        console.log('done')
        userCallback();
    );


, function(err)
    console.log("User For Loop Completed");
);

【讨论】:

谢谢!这是一个后续问题:***.com/questions/31815917/…

以上是关于Node.js 中 For 循环中的 async.waterfall的主要内容,如果未能解决你的问题,请参考以下文章

node.js 中的 async.eachSeries

node.js 中的 async.eachSeries

for 循环内的 async.waterfall 转义 for 循环

node.js 中的空循环行为

Node.js 同步循环或迭代异步语句

Node.js - Async.js:并行执行如何工作?