2013-12-10 189 views
1

全部,閉包&異步node.js函數

試圖讓我的頭在node.js上下文(異步調用)中關閉。

我有以下代碼:

timer = setInterval(pollOID, 1000); 

function pollOID() { 
    for (channel in channels) { 
     session.get({ oid: channels[channel].oid }, function (varbinds) { 
       console.log("The " + channels[channel].name + " is " + varbinds); 
     }); 
    } 
} 

代碼投票第二使用中的setInterval回調一個循環來查詢幾個SNMP實體路由器的每個數據SNMP路由器。 session.get函數有一個異步回調來處理來自路由器的結果。

SNMP位工作正常,我的問題是關於如何在會話異步回調內持續循環變量通道的值。

我得到如下結果:

The Download Attenuation is 7.5 
The Download Attenuation is 361600 
The Download Attenuation is 60 

所以循環變量通道正在改變每次調用session.get作爲函數返回從路由器正確的值。我的問題是,channels [channel] .name使用通道的當前值,在回調返回時,通道已經結束並且通道爲2(第三個循環,即名稱字符串「download attenuation」)。所以我需要在session.get回調中保留通道的值,以便在回調被調用時的值,以便在session.get回調中使用正確的通道[channel] .name。

我知道我必須使用閉包,但嘗試了很多不同的方法後,我無法正常工作。任何線索指向正確的方向?謝謝!

回答

6

您可以創建一個簡單的閉包來保存本地副本channel

function pollOID() { 
    for (channel in channels) { 
     (function(channel){ 
     session.get({ oid: channels[channel].oid }, function (varbinds) { 
       console.log("The " + channels[channel].name + " is " + varbinds); 
     }); 
    })(channel); 
    } 

或者你也可以使用bind來傳入參數,但上下文會在回調中改變。

for (channel in channels) { 
    session.get({ oid: channels[channel].oid }, (function (channel, varbinds) { 
      console.log("The " + channels[channel].name + " is " + varbinds); 
    }).bind(this, channel)); 
} 

正如你猜你的問題是,由於這是一個共享變量,由當時的回調調用你的循環將通過已經運行和渠道將舉行列舉的最後一個key回調訪問channelchannels

+0

謝謝PSL。關閉的第一個建議不起作用,因爲「渠道」沒有與原來的值保持一致,但第二個建議與綁定沒有關係。我不確定爲什麼第一個建議不起作用,正如我想的那樣,以及從我應該關閉的(有限)理解中得出的。 – deandob

+1

@deandob本應該工作,請嘗試這種方式。 http://jsfiddle.net/pRLVC/您可以在您的代碼中使用相同的概念。 – PSL

+2

我發現在循環塊內部聲明一個局部變量並且在閉包體中使用它''var currentChannel = channel;',然後在閉包中使用currentChannel就不那麼容易混淆了。但是現在JS中'(函數(a){/*...*/})(a);'模式非常普遍,值得習慣。 –

0

另一種方法是使用async module,這簡化了控制流程,可以在引入更多異步調用時提高可讀性。

function pollOID() { 
    for (channel in channels) { 
     (function(channel){ 
     session.get({ oid: channels[channel].oid }, function (varbinds) { 
      console.log("The " + channels[channel].name + " is " + varbinds); 
     }); 
    })(channel); 
} 

成爲

function pollOID() { 
    var log = function(channel, cb){ 
     session.get({ oid: channel.oid }, function (varbinds) { 
      console.log("The " + channel.name + " is " + varbinds); 
      cb(); // Moves onto next element in channels when cb is called 
     }); 
    }; 
    var allDone = function(err, result) { 
     // all tasks are complete 
    }; 
    async.each(channels, log, allDone); 
} 

async.each將並行運行,所以如果它需要按順序使用async.eachSeries代替。

+0

謝謝。我假設也可以使用新的ES7異步功能。 – deandob