2017-10-19 104 views
0

我正在編寫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

回答

2

這是一個常見問題,稱爲「閉合循環變量」。問題是,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
  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

  • 亞馬遜控制檯的碼檢驗建議我,這是一個不好的做法,在循環中創建函數
  • 爲了解決這個問題我建議你看看async npm模塊。你可以在那裏找到each