最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Closures & async node.js functions - Stack Overflow

programmeradmin1浏览0评论

All,

Trying to get my head around closures in a node.js context (async calls).

I have the following code:

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);
        });
    }
}

The code polls a router for SNMP data each second using a loop in the setInterval callback to query the router for several SNMP entities. The session.get function has an async callback to process the results from the router.

The SNMP bits are working fine, my question is about how to persist the value of the loop variable channel inside the session async callback.

I get the following results:

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

So the loop variable channel is changing for each call to session.get as the function is returning the correct value from the router. My problem is that channels[channel].name uses the current value of channel which by the time the callback has returned the loop has ended and channel is 2 (the third loop, which is the name string "download attenuation"). So I need to persist the value of channel inside the session.get callback to the value it was when the callback is called so the correct channels[channel].name is used in the session.get callback.

I know I have to use a closure for this but after trying a number of different approaches I can't get it working properly. Any clues to point me in the right direction? Thanks!

All,

Trying to get my head around closures in a node.js context (async calls).

I have the following code:

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);
        });
    }
}

The code polls a router for SNMP data each second using a loop in the setInterval callback to query the router for several SNMP entities. The session.get function has an async callback to process the results from the router.

The SNMP bits are working fine, my question is about how to persist the value of the loop variable channel inside the session async callback.

I get the following results:

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

So the loop variable channel is changing for each call to session.get as the function is returning the correct value from the router. My problem is that channels[channel].name uses the current value of channel which by the time the callback has returned the loop has ended and channel is 2 (the third loop, which is the name string "download attenuation"). So I need to persist the value of channel inside the session.get callback to the value it was when the callback is called so the correct channels[channel].name is used in the session.get callback.

I know I have to use a closure for this but after trying a number of different approaches I can't get it working properly. Any clues to point me in the right direction? Thanks!

Share Improve this question edited Dec 10, 2013 at 21:59 PSL 124k21 gold badges256 silver badges243 bronze badges asked Dec 10, 2013 at 20:59 deandobdeandob 5,2805 gold badges28 silver badges40 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 6

You can create a simple closure to hold on to a local copy of 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);
  }

Or you can also use bind to pass in the argument, but the context will change inside the callback though.

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

And as you guessed your issue is due to accessing channel in the callback which is a shared variable and by the time the callback is invoked your for loop would have run through and channel will be holding the last key enumerated from channels.

Another method is to use async module, and this simplifies control flow which can improve readability as more async calls are introduced.

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);
}

bees

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 plete
    };
    async.each(channels, log, allDone);
}

async.each will run in parallel so if it needs to be in order, use async.eachSeries instead.

发布评论

评论列表(0)

  1. 暂无评论