N Klosterman
N Klosterman

Reputation: 1251

Node.js: Continuous execution from settimeout when expecting node to do nothing until settimeout interval over

I'm writing a notifier for 3 deal of the day websites in node. I go and parse the body of the webpage to grab the details. In the details there is a timer for the how long the deal will last. I'm reading that timer and trying to use setTimeout/setInterval to set when the function should execute again. However the function calls are continuous instead of waiting.

Pseudo code of what I'm doing:

var getData = function(url) {
request(url, function(err, resp, body){                                                                                      
       if(err)   throw err; 
//process the body getting the deal information and timer
setTimeout(getData(url),timer*1000);
}

getData(url1);
getData(url2);
getData(url3);

Full code here.

I want the program to run, continually calling itself with the new timeouts for the webpages.

I'm a Node.js newbie so I'm guessing I'm getting tripped up with the async nature of things.

Any help is greatly appreciated.

EDIT: more simply :

var hello = function(){
console.log("hello");
setTimeout(hello(),25000);
}

hello();

prints out hello continuously instead of hello every 2.5s. What am I doing wrong?

Upvotes: 1

Views: 1957

Answers (2)

Paul
Paul

Reputation: 141887

The problem is evident in your hello example, so lets take a look at that:

var hello = function(){
    console.log("hello");
    setTimeout(hello(),25000);
}

hello();

In particular this line: setTimeout(hello(),25000);. Perhaps you are expecting that to call hello after a 25 second timeout? Well it doesn't, it calls hello immediately, (that's what hello() does in Javascript, and there is nothing special about setTimeout), and then it passes the return value of hello() to setTimeout, which would only make sense if hello() returned another function. Since hello recursively calls itself unconditionally, it doesn't ever return, and setTimeout will never be called. It's similar to doing the following:

function hello() {
  return doSomething(hello());
}

Is it clear why doSomething will never be called?

If you want to pass a function to setTimeout, just pass the function itself, don't call it and pass the return value: setTimeout(hello, 25000);.

Your fixed code:

var getData = function(url) {
  request(url, function(err, resp, body){                                                                                      
    if(err)   throw err; 
    //process the body getting the deal information and timer
    setTimeout(getData, timer*1000, url);
  });
};

getData(url1);
getData(url2);
getData(url3);

Noticed that I passed the argument for getData as a third argument to setTimeout.

Upvotes: 2

Joe
Joe

Reputation: 42656

What's happening is 'request' is being run as soon as getData is called. Do you want getData to be the function you call to start the timer, or the one that loads the data?

var getData = function(url) {
    function doRequest(url) {
        request(url, function(err, resp, body) {                                                                                      
        if(err)   throw err; 
        //process the body getting the deal information and timer
    }
    setTimeout(doRequest(url),timer*1000);
}

getData(url1);
getData(url2);
getData(url3);

What you want is 'setTimeout' to point to a function (or anonymous function/callback) that you run after the timer expires. As you originally wrote, getData was immediately calling request (and then calling getData again after your timer)

Upvotes: 0

Related Questions