Javascript 将数据传递到node.js回调-异步问题

Javascript 将数据传递到node.js回调-异步问题,javascript,node.js,asynchronous,callback,Javascript,Node.js,Asynchronous,Callback,以下面的代码为例,其中一个对象数据用一些值初始化,然后由一些时间密集型函数(如数据库访问)处理。如果功能成功,成功的数据项的名称将打印到控制台。否则,将打印故障通知: data = {first: 'someinfo', second: 'somemoreinfo', third: 'evenmoreinfo'}; for (var item in data) { timeIntensiveFunction(item, data[item], function(err)

以下面的代码为例,其中一个对象
数据
用一些值初始化,然后由一些时间密集型函数(如数据库访问)处理。如果功能成功,成功的
数据
项的名称将打印到控制台。否则,将打印故障通知:

data = {first:  'someinfo',   second:  'somemoreinfo',   third:  'evenmoreinfo'};

for (var item in data) {
    timeIntensiveFunction(item, data[item], function(err) {
        if (!err) {
            console.log(item + ' processed successfully');
        } else {
            console.log(item + ' failed');
        }
    });
}
假设函数对所有三个数据项都成功,您希望控制台显示此信息:

first processed successfully
second processed successfully
third processed successfully
相反,它将显示此,假设第一次数据库访问所需的时间比
for
循环所需的时间长:

third processed successfully
third processed successfully
third processed successfully
这是因为控制台日志记录是在回调中完成的,只有在
for
循环完成后才会调用,因为
timeIntensiveFunction()
需要很长时间在调用第一个回调时,
项已具有其最后一个值,
第三个值


如何将项的“当前”值传递到回调中?

问题是因为它只使用最后一个项调用回调

您可以使用类似于bellow的函数绑定每个项目

var printStatus = function(item){
    return function(err) {
        if (!err) {
            console.log(item + ' processed successfully');
        } else {
            console.log(item + ' failed');
        }
    }
}

for (var item in data) {
    timeIntensiveFunction(item, data[item], printStatus(item));
}
这是javascript中闭包的常见“陷阱”。一种解决方法是将函数调用包装在匿名函数中,然后重新查看
。像这样:

for (var item in data) {
    (function(item){
        timeIntensiveFunction(item, data[item], function(err) {
           if (!err) {
               console.log(item + ' processed successfully');
           } else {
               console.log(item + ' failed');
           }
        });
   })(item);
}

如果您正在寻找一个使异步任务更容易处理的库,请查看

输出

time intensive task started: first
task complete: first
time intensive task started: second
task complete: second
time intensive task started: third
task complete: third

对于希望了解如何在没有库的情况下执行此操作的用户,您可以查看此答案的修订历史。

JavaScript中的对象键没有顺序。考虑一个简单的有序数组,如<代码> [第一个]、“第二个”、“第三个”[/COD]或一个带有对象<代码> [{ID:1]“},{ID:“第二”},{ID:“第三”}/<代码>。问题在于,无论排序如何,节点都将以某种顺序处理三个
数据
项。假设
timeIntensiveFunction()
完成
循环所需的时间长于
,则所有三个控制台行都将显示
项的最后一个值,而不是
timeIntensiveFunction()
@go-oleg:实际上我认为它是一个有效的副本。For in和For循环没有什么区别,OP已经意识到在循环结束后异步调用回调,所有必要的信息都存在。这并不保证项目得到处理sequentially@maček我想它给了,因为它将仅使用相应的
项调用函数
printStatus
。它保证按顺序对项调用timeIntensiveFunction,但不保证回调的时间。但这就是异步性和回调函数的核心所在。此外,这基本上与我的答案相同,但风格不同。如果你自己编写
timeIntensiveFunction
,这会有所帮助,如果你是从模块中获得的,你就不会想用自己的方式来包装它function@TheEnvironmentalist我想我没有理解你的意思,我没有包装
timeIntensiveFunction
。我只是包装了我的回调函数,我将定义它,而函数
timeIntensiveFunction
需要回调,而且它得到了回调,我认为它来自模块或我自己的回调并不重要。这违背了
for
loopWell的目的,这就是重点;
for
循环不能(轻松地)用于异步串行处理。如果
async.series
不适合您,可能您希望查看Promises api和链
。然后
调用Promises对象。但这会给本来相对简单的过程增加很多重量。node.js
for
循环是有原因的。
数据
对象来自数据库。我不知道什么数据
timeIntensiveFunction()
将提前运行,甚至不知道它将运行多少次。我提到了两个库,它们使处理这些事情变得更容易,并且它们将大量清理语法。查看
异步
承诺
。我只打算提供一个原生JS解决方案。您可以进一步抽象它,使它更漂亮。我考虑过这一点,但它很混乱,我会为大约二十个不同的函数提供包装器。您可以始终使用下划线()或.forEach语法之类的库(如果您的javascript实现支持的话)在一行而不是两行中执行迭代和回调函数/耸肩这大概是你能得到的最好的了。
time intensive task started: first
task complete: first
time intensive task started: second
task complete: second
time intensive task started: third
task complete: third