在循环中使用其他参数进行回调

问题描述:

我正在编写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(....); 
    }); 
} 

这里有两个问题。

  1. 我不明白为什么,但里面的回调传递给foo.method1...我一直的v1相同的值(我猜想,这是该数组中的最后一个)。

  2. 亚马逊控制台的码检验建议我,这是一个不好的做法,在循环中创建一个函数:

不要在循环中做功能。

我想,p.1与p.2相关:-)这就是为什么我试图创建一个命名函数并将其引用传递给foo.method1。但它不起作用,因为我无法在那里传递其他参数v1s3。我只能换其呼叫,如:

foo.method1(params, function(err, data1) { 
      myCallback(err, data1, v1, s3); 
    }); 
  • 什么没有意义,因为结果是一样的。

提示foo.method1显然是异步的。

我怀疑如何解决这个问题?

+0

'v1'在每个函数的关闭中被捕获。所有的函数引用'v1'的相同的活动副本,这是调用函数时的最后一个值。一个解决方案是使用'let',如下所述:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Cleaner_code_in_inner_functions – skirtle

这是一个常见问题,称为“闭合循环变量”。问题是,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中异步代码的未来吨。这将允许您轻松管理异步操作,例如,当所有这些操作完成时(如果您想这样做),执行一些代码。

+0

在这个aproach中的forEach问题当'collection'中的所有'items'都被上传时,你不能附加回调。 –

+0

@AlexandruOlaru我不明白为什么比任何其他典型方法(绑定,IIFE,函数发生器)都更不可能附加这样的回调函数。你的答案中的IIFE是否允许以某种方式附加这样的回调:“.forEach'不是? – JLRishe

+0

那么如何将异步函数的'.forEach'的结果附加回调函数呢?您需要实现一个门,或者使用现有的工具async.each(data.foo,putOnS3,finalCallback)'。 IIFE是第一个问题的回答,第二个问题是'async.each',其中有两个不同的问题。同意“绑定”也适用于范围问题。 –

  1. 我不明白为什么,但里面的回调传递给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

  1. 亚马逊控制台的码检验建议我,这是一个不好的做法,在循环中创建函数
开始=“2”>

为了解决这个问题我建议你看看async npm模块。你可以在那里找到each