16

Here's my issue. I have this function to test proxy servers.

function crawl() {
    var oldstatus = document.getElementById('status').innerHTML;
    document.getElementById('status').innerHTML = oldstatus + "Crawler Started...<br />";
    var url = document.getElementById('url').value;
    var proxys = document.getElementById('proxys').value.replace(/\n/g,',');

    var proxys = proxys.split(",");

    for (proxy in proxys) {
        var proxytimeout = proxy*10000;
        setTimeout(doRequest(url,proxys[proxy]), proxytimeout);
    }
}

I want the 'doRequest()' function to be called in roughly 10 second intervals but even with the setTimeout() the functions are called immediately.

Any ideas are welcome, thanks.

PS: Even if I put an arbitrary value for 'proxytimout' it has no effect.

outis
  • 68,704
  • 19
  • 132
  • 197
Ben
  • 3,981
  • 6
  • 34
  • 60

3 Answers3

14

As you give the function to the setTimeout in that form, the function is executed instead of passed to the setTimeout. You have three alternatives to make it work:

Give first the function, then the timeout and the parameters as the last arguments:

setTimeout(doRequest, proxytimeout, url, proxys[proxy]);

Or just write a string that will be evaluated:

setTimeout('doRequest('+url+','+proxys[proxy]+')', proxytimeout);

Third style is to pass an anonymous function that calls the function. Note that in this case, you have to do it in a closure to prevent the values from changing in the loop, so it gets a bit tricky:

(function(u, p, t) {
    setTimeout(function() { doRequest(u, p); }, t);
})(url, proxys[proxy], proxytimeout);

The second format is a bit hacky, but works nevertheless if the arguments are scalar values (strings, ints etc). The third format is a bit unclear, so in this case the first option will obviously work best for you.

Tatu Ulmanen
  • 115,522
  • 31
  • 176
  • 180
  • 3
    Correct me if I'm wrong, but since this is happening inside a loop, the second method you've given won't work. The value of `proxy` will change because there's no closure created. – nickf Jan 10 '10 at 14:13
  • @nickf: I was about to say that. Also, the third option violates `eval is evil`. – SLaks Jan 10 '10 at 14:13
  • @nickf, you're true, I overlooked that point. I've updated my answer. – Tatu Ulmanen Jan 10 '10 at 14:28
  • Thanks that's a huge help, this is an incredible community! – Ben Jan 10 '10 at 14:32
  • the setTimeout(doRequest, proxytimeout, url, proxys[proxy]) won't work in IE, right? – kenny Jan 31 '10 at 20:38
1

This line here is the problem:

setTimeout(doRequest(url,proxys[proxy]), proxytimeout);

Writing doRequest() is actually calling the function. What you want is to pass the function itself:

setTimeout(doRequest, proxytime, url, proxys[proxy]);
nickf
  • 499,078
  • 194
  • 614
  • 709
0

You're misunderstanding the setTimeout function.

The setTimeout function takes a function and executes it later.
By writing setTimeout(doRequest(url,proxys[proxy]), proxytimeout), you're _calling the doRequest function (immediately), and passing the result (assuming that it returns another function) to setTimeout.

You need to pass doRequest's parameters to setTimeout, like this:

setTimeout(doRequest, proxytimeout, url, proxys[proxy]);

This will pass setTimeout the doRequest function itself (without calling it first), and will also pass it the parameters to give to doRequest when it finally calls it.

SLaks
  • 800,742
  • 167
  • 1,811
  • 1,896