循环中带有附加参数的回调

Callback with additional parameters in loop

我正在编写 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. 亚马逊控制台的代码检查器告诉我在循环中创建函数是一种不好的做法:

Don't make functions within a loop.

我猜,p.1 与 p.2 有某种关联 :-) 这就是为什么我试图创建一个命名函数并将其引用传递给 foo.method1 的原因。但它不起作用,因为我无法在那里传递额外的参数 v1s3。我只能像这样包装它的调用:

    foo.method1(params, function(err, data1) { 
          myCallback(err, data1, v1, s3);
    });

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

我不知道如何解决这个问题?

这是一个常见问题 "closing over a loop variable"。问题是 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,到目前为止,它是JavaScript 中异步代码的未来。这将允许您轻松管理异步操作,例如,在所有这些操作完成时执行一些代码(如果您愿意的话)。

  1. I do not understand why, but inside callback passed to foo.method1... I have always the same value of v1 (I guess that it is last one).

你得到相同的 v1 项目因为你正在迭代异步函数,所以它在内部做了什么,它正在迭代你的 for,然后将 x 闭包(data.foo.length) 最后一个 i 值`

那你怎么解决这个问题呢?您可以将 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. The Code checker of Amazon console advises me that it is a bad practice to create a function within a loop

要解决此问题,我建议您查看 async npm module. You can find there each