1

I have the following Node.js code:

var exec=require('child_process').exec;

var base_ctrl_port=8118;
var base_data_port=9050;
var nConns=10;

watchdogCycle();
setInterval(watchdogCycle, 60000);   //check health every 60 seconds...

function watchdogCycle(){
        console.log("\n");
        for(var i=0;i<nConns;i++){
                var data_port=base_data_port+i;
                data_port=data_port+"";
                var curl=exec('curl -b -s --socks5 localhost:'+data_port+' http://ifconfig.me',{timeout:10000},
                function(err,stdout,stderr){
                        console.log(stdout);
                        if(err!=null){
                                getNewIP(i);   //PROBLEM: i is always 10!!!
                        }
                });
        }
}

function getNewIP(offset){
        console.log("Getting new IP address for tor data port: "+(base_data_port+offset+0)+"...");
        var ctrl_port=base_ctrl_port+offset;
        var nc=exec('(echo AUTHENTICATE \'\"xxxxxx\"\'; echo SIGNAL NEWNYM; echo quit) | nc localhost '+ctrl_port,
        function(err,stdout,stderr){
                console.log(stdout);
        });
}

The problem is that the parameter, i, into getNewIP(i) is always 10!

I've read up a bit about recursion, but I don't know how to modify this code so that i is 0..9 and not always 10.

Many thanks in advance,

Paul D. Waite
  • 96,640
  • 56
  • 199
  • 270
Eamorr
  • 9,872
  • 34
  • 125
  • 209

2 Answers2

3

This is a problem with closures...

Try this:

for(var i=0;i<nConns;i++){
    var data_port=base_data_port+i;
    data_port=data_port+"";
    (function (i){ // <-----
        var curl=exec('curl -b -s --socks5 localhost:'+data_port+' http://ifconfig.me',{timeout:10000},
            function(err,stdout,stderr){
                console.log(stdout);
                if(err!=null){
                    getNewIP(i);   //PROBLEM: i is always 10!!!
                }
            });
    })(i); // <-----
}
Gabriel Llamas
  • 18,244
  • 26
  • 87
  • 112
  • @Eamorr Understanding why this works is what seperates a javascript beginner from a proper javascript developer. The asynchronous function doesn't get called in the same context as you think it would (the value of i isn't the immediate value outside the function definition). Read this for a proper explanation: http://stackoverflow.com/questions/1451009/javascript-infamous-loop-problem. Protip: Read "javascript, the good parts" by douglas crockford. It is a small book. – Munim Jun 20 '13 at 13:17
2

Simply saying your problem is proportional to this:

for(i = 0; i < 10; i++){
    setTimeout(function(){ alert(i);}, 1000);
}

In order to solve the problem, you can do wrap your code in a new function:

for(i = 0; i < 10; i++){
    (function(otherI){
        setTimeout(function(){ alert(otherI); }, 1000);
    })(i)
}

This is a known problem people often have when using closures!

You can refer to this thread for more information, as the problems are basically the same: Passing functions to setTimeout in a loop: always the last value?

This is also a good reference: Javascript infamous Loop issue?

For a more readable syntax, you can also do something like:

for(i = 0; i < 10; i++){
    with({i: i}){
        setTimeout(function(){ alert(i);}, 1000);
    }
}
Community
  • 1
  • 1
Renato Gama
  • 16,431
  • 12
  • 58
  • 92