Node.js中的asynchronous代码和循环?

我已经在asynchronous编程方面做了好几个小时的研究,但我似乎无法在Node中掌握这个单一的概念,所以我想知道这里有人能帮助我。

我已经写了下面的代码示例来返回/输出一个简单的string,这是一个对象string的串联:

var itemCollection = { item1 : [{ foo : "bar" }, { foo : "bar" }, { foo : "bar" }], item2 : [{ foo : "bar" }, { foo : "bar" }, { foo : "bar" }], item3 : [{ foo : "bar" }, { foo : "bar" }, { foo : "bar" }] } var aString = ""; for(item in itemCollection){ for (var i = 0; i < itemCollection[item].length; i++) { var anItem = itemCollection[item][i]; //someFunctionThatDoesALongIOOperation takes an item as a param, plus a callback. someFunctionThatDoesALongIOOperation(anItem, function(dataBackFromThisFunction){ // Do something with the data returned from this function aString += dataBackFromThisFunction.dataToAppend; }); }; } console.log(aString); 

所以据我所知,JavaScript以外的其他语言会同步运行一些someFunctionThatDoesALongIOOperation ,并且脚本会以“阻塞模式”运行。 这意味着aString的值将以正确的值返回/输出。

但是,当Node asynchronous运行时,代码可以在任何时候继续运行,任务可能无法按顺序完成。 这是因为事件循环在Node中的工作方式。 我想我得到这个。

所以这就是我的问题来了。如果我想要值的aString返回/输出与其他语言中的正确值,我将需要做我的代码示例中的循环? 或者用更多的技术术语来提出我的问题:使aString返回预期结果的正确方法是什么,以便在脚本完成执行后,IO操作(需要较长时间运行)没有完成,因为aString已经被退回?

我希望我的问题是有道理的,如果没有,请让我知道,我会在适当的地方进行编辑。

谢谢

由于您对每个项目应用的函数是asynchronous的,因此处理它们的循环也必须是asynchronous的(同样,消耗此循环结果的函数也必须是asynchronous的)。 看看Bob Nystrom的“你的function是什么颜色?” 为更多的洞察力在这一点上。

有两种方法可以做到这一点(都使用caolan的async库来包装所有讨厌的callback逻辑):

  • 一次执行一个asynchronous操作,等待前一个完成,然后才能开始下一个。 这可能与传统的同步循环的运行方式非常相似。 我们可以使用async.reduce来做到这async.reduce

     async.reduce(itemCollection, "", function(memo, item, callback) { someFunctionThatDoesALongIOOperation(item, function(dataBackFromThisFunction) { callback(null, memo + dataBackFromThisFunction.dataToAppend); }); }, function(err, result) { var aString = result; }); 
  • 当然,如果我们实际上没有获得好处,并且一次执行许多事情,那么就没有什么意义了。 我们可以并行执行所有的asynchronous操作,然后一步一步地完成所有的asynchronous操作。 我发现如果处理每个项目需要一些很长的操作(比如networkingI / O),那么这是非常棒的,因为我们可以一次启动并等待很多请求。 我们使用async.map来实现这一点:

     async.map(itemCollection, function(item, cb) { someFunctionThatDoesALongIOOperation(item, function(dataBackFromThisFunction) { cb(null, dataBackFromThisFunction.dataToAppend); }); }, function(err, results) { var aString = results.join(''); });