在循环中使用其他参数进行回调
我正在编写Node.JS lambda函数,我需要使用回调调用一些API函数并传递其他参数。在循环中使用其他参数进行回调
代码如下:
var s3 = ...;
for (var i = 0; i < data.foo.length; i++) {
var v1 = data.foo[i].name;
console.log("Loop: " + v1);
var params = { ... };
foo.method1(params, function(err, data1) {
console.log("Method1: " + v1);
s3.putObject(....);
});
}
这里有两个问题。
我不明白为什么,但里面的回调传递给
foo.method1...
我一直的v1
相同的值(我猜想,这是该数组中的最后一个)。亚马逊控制台的码检验建议我,这是一个不好的做法,在循环中创建一个函数:
不要在循环中做功能。
我想,p.1与p.2相关:-)这就是为什么我试图创建一个命名函数并将其引用传递给foo.method1
。但它不起作用,因为我无法在那里传递其他参数v1
和s3
。我只能换其呼叫,如:
foo.method1(params, function(err, data1) {
myCallback(err, data1, v1, s3);
});
- 什么没有意义,因为结果是一样的。
提示:foo.method1
显然是异步的。
我怀疑如何解决这个问题?
这是一个常见问题,称为“闭合循环变量”。问题是,v1
将继续改变,而您等待回调执行,并且您看到的v1
将是最后一个值。
一种方法来解决这个问题:在v1
变量绑定你的回调中:
var s3 = ...;
for (var i = 0; i < data.foo.length; i++) {
var v1 = data.foo[i].name;
console.log("Loop: " + v1);
var params = { ... }; // v-- extra parameter
foo.method1(params, function(v1inner, err, data1) {
console.log("Method1: " + v1);
s3.putObject(....);
}.bind(null, v1)); // <-- bind
}
更好的方法:使用.forEach
使每个迭代创建一个新v1
变量:
var s3 = ...;
data.foo.forEach(function (datai) {
var v1 = datai.name;
console.log("Loop: " + v1);
var params = { ... };
foo.method1(params, function(err, data1) {
console.log("Method1: " + v1);
s3.putObject(....);
});
});
编辑:如果您正在寻找一种更加无压力的方式来处理异步代码,我会建议查看Promises,它目前是JavaScrip中异步代码的未来吨。这将允许您轻松管理异步操作,例如,当所有这些操作完成时(如果您想这样做),执行一些代码。
在这个aproach中的forEach问题当'collection'中的所有'items'都被上传时,你不能附加回调。 –
@AlexandruOlaru我不明白为什么比任何其他典型方法(绑定,IIFE,函数发生器)都更不可能附加这样的回调函数。你的答案中的IIFE是否允许以某种方式附加这样的回调:“.forEach'不是? – JLRishe
那么如何将异步函数的'.forEach'的结果附加回调函数呢?您需要实现一个门,或者使用现有的工具async.each(data.foo,putOnS3,finalCallback)'。 IIFE是第一个问题的回答,第二个问题是'async.each',其中有两个不同的问题。同意“绑定”也适用于范围问题。 –
- 我不明白为什么,但里面的回调传递给foo.method1 ......我一直V1(我猜想,这是最后一个)的值相同。
你会得到相同的v1
项目导致你迭代异步函数,所以internaly它做什么,这是你的迭代for
,然后将x
关闭(data.foo.length
)与最后我value`
那么你如何解决这个问题?你可以将你的i
包装在一个IIFE中,这样就不会共享上下文。
(function(i) {
var v1 = data.foo[i].name;
console.log("Loop: " + v1);
var params = { ... };
foo.method1(params, function(err, data1) {
console.log("Method1: " + v1);
s3.putObject(....);
});
})(i);
此代码将创建一个适当的i
值的特殊范围。
第二种方法是使用let i
而不是var i
,这也将做与上述代码相同的技巧。更多关于let
开始=“2”>
- 亚马逊控制台的码检验建议我,这是一个不好的做法,在循环中创建函数
'v1'在每个函数的关闭中被捕获。所有的函数引用'v1'的相同的活动副本,这是调用函数时的最后一个值。一个解决方案是使用'let',如下所述:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Cleaner_code_in_inner_functions – skirtle