简体   繁体   English

Node.js中的异步代码和循环?

[英]Asynchronous code and loops within Node.js?

I've done hours of research on asynchronous programming, but I just can't seem to grasp this one single concept within Node, so I was wondering if someone here could help me. 我已经进行了数小时的异步编程研究,但似乎无法在Node中掌握这一概念,因此我想知道这里是否有人可以帮助我。

I've written the following code sample to return / output a simple string which is a concatenation of strings from an object: 我编写了以下代码示例,以返回/输出一个简单的字符串,该字符串是来自对象的字符串的串联:

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

So from what I understand, languages other than Javascript would run someFunctionThatDoesALongIOOperation synchronously and the script would run in a 'blocking mode'. 因此,据我了解,除Javascript之外的其他语言将同步运行someFunctionThatDoesALongIOOperation且脚本将在“阻止模式”下运行。 This would mean that the value aString would get returned / outputted with its correct value. 这意味着将使用正确的值返回/输出值aString

However, as Node runs asynchronously , code can continue to run at anytime and tasks may not complete in order. 但是,由于Node 异步运行,因此代码可以随时继续运行,并且任务可能无法按顺序完成。 This is because of the way the event loop works in Node. 这是因为事件循环在Node中的工作方式。 I think I get this. 我想我明白了。

So this is where my question comes in. If I wanted the value aString to be returned / outputted with its correct value like it would in other languages, what would I need to do to the loops within my code example? 所以这就是我的问题所在。如果像其他语言一样,如果要以正确的值返回/输出aString值,我该对代码示例中的循环做些什么? Or to put my question in more technical words: What is the correct approach for making aString return the expected result, so that IO operations (which take a longer amount of time to run) aren't completed after the script has finished executing when aString has already been returned? 或者用更专业的词来回答我的问题:什么是使aString返回预期结果的正确方法,以便在aString脚本执行完后,IO操作(需要更长的运行时间)没有完成已经退货了吗?

I hope my question makes sense, if it doesn't, please let me know and I will make edits where appropriate. 我希望我的问题有意义,如果没有,请告诉我,我将在适当的地方进行编辑。

Thank you 谢谢

Since the function you apply to each item is asynchronous, the loop that processes them also must be asynchronous (likewise the function that consumes the result of this loop must also be async). 由于应用于每个项目的函数是异步的,因此处理它们的循环也必须是异步的(同样,消耗此循环结果的函数也必须是异步的)。 Check out Bob Nystrom's "What Color is Your Function?" 查看Bob Nystrom的“您的功能是什么颜色?” for more insight on this particular point. 有关此特定点的更多见解。

There's two ways to do this (both using caolan's async library to wrap all the nasty callback logic): 有两种方法可以做到这一点(都使用caolan的async来包装所有讨厌的回调逻辑):

  • Do one async operation one at a time, waiting for the previous to finish before the next can begin. 一次执行一个异步操作,等待上一个操作完成,然后再开始下一个操作。 This is probably most similar to the way a traditional synchronous loop runs. 这可能与传统同步循环的运行方式最相似。 We can do this with async.reduce : 我们可以使用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; }); 
  • Of course, there's little point in having async code if we don't actually reap it's benefits and execute many things at once. 当然,如果我们没有真正获得异步代码的好处并立即执行许多操作,那么拥有异步代码就没有什么意义了。 We can do all the async operations in parallel and reduce all at once in a single step afterwards. 我们可以并行执行所有异步操作,然后在单个步骤中一次减少所有异步操作。 I've found this is great if processing each item requires some long operation such as network I/O, since we can kick off and wait for many requests at once. 我发现如果处理每个项目需要一些长时间的操作(例如网络I / O),那么这很好,因为我们可以立即启动并等待许多请求。 We use async.map to achieve this: 我们使用async.map实现此目的:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM