views:

460

answers:

4

I am not too familiar with the specifics of every javascript implementation on each browser. I do know however that using setTimeout, the method passed in gets called on a separate thread. So would using a setTimeout recursively inside of a method cause its stack to grow indefinitely until it causes a Stack Overflow? Or would it create a separate callstack and destroy the current frame once it goes out of focus? Here is the code that I'm wondering about.

function pollServer()
{
 $.getJSON("poll.php", {}, function(data){
  window.setTimeout(pollServer, 1000);
 });
}

window.setTimeout(pollServer, 0);

I want to poll the server every second or so, but do not want to waste CPU cycles with a 'blocking loop' - also I do not want to set a timelimit on how long a user can access a page either before their browser dies.

EDIT

Using firebug, I set a few breakpoints and by viewing the "Script -> Stack" panel saw that the call stack is literally just "pollServer" and it doesn't grow per call. This is good - however, do any other implementations of JS act differently?

+1  A: 

I am not sure if it would create a stack overflow, but I suggest you use setInterval if the period is constant.

This is how prototype implements its PeriodicalExecuter.

// Taken from Prototype (www.prototypejs.org)
var PeriodicalExecuter = Class.create({
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  execute: function() {
    this.callback(this);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.execute();
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
});
Sinan Taifour
This seems pretty solid and similar to my implementation. If this is guaranteed to not cause a SO, then so it seems neither will my code.
nlaq
The big difference is that it uses `setInterval` as opposed to `setTimeout`, which is the source of your concern. If I was in your place I'd go for `setInterval`, and save myself the headache.
Sinan Taifour
Is there a jQuery version of prototype's PeriodicalExecutor ?
JG
A: 

setTimeout does not grow the callstack, because it returns immediately. As for whether your code will run indefinitely in any browser, I'm not sure, but it seems likely.

allyourcode
A: 

setTimeout executes sometime later in the future in the event pump loop. Functions passed to setTimeout are not continuations.

If you stop and think about it, what useful purpose or evidencec is there that the call stack is shared by the timeout function.

  • If they were shared what stack would be shared from the setter to the timeout function ?
  • Given the setter can do a few returns and pop some frames - what would be passed ?
  • Does the timeout function block the original thread ?
  • Does the statement after the setTimeout function execute after the timeout executes ?

Once you answer those questions it clearly becomes evident the answerr is NO.

mP
A: 

take a look at the jQuery "SmartUpdater" plugin.

http://plugins.jquery.com/project/smartupdater

Following features are available:

  • stop() - to stop updating.
  • restart() - to start updating after pause with resetting time interval to minTimeout.
  • continue() - to start updating after pause without resetting time interval.
  • status attribute - shows current status ( running | stopping | undefined )
  • updates only if new data is different from the old one.
  • multiplies time interval each time when data is not changed.
  • handle ajax failures by stopping to request data after "maxFailedRequests".
vadimk