1

I am making a chrome extension for personal use that will recursively call setTimeout. I would like to make sure that under no circumstances does this extension accidentally produce multiple chains of setTimeouts.

I have made it so that when I click the browser action it calls clearTimeout. However, I worry about when I reload the extension could the old chain of timeouts continue? And there may be other scenarios I am not thinking of. Is there a tried and true method to prevent accidentally creating multiple chains of timeouts?

It looks like there is no way to enumerate active javascript timers:Viewing all the timouts/intervals in javascript?

Community
  • 1
  • 1
  • Can you add some code? Because it's not entirely clear how exactly you "recursively call" setTimeout. In any case if you do it in the background page script then all of the timers will be destroyed on reload. Only injected content script survive unless you also reload the web page(s). Also, I'd recommend using `chrome.alarms` API. – wOxxOm Oct 16 '15 at 17:53

2 Answers2

1

I've solved a similar case like this before:

var timer;
function foo(){
  if(!timer)
    timer = setTimeout(function (){
      //should print once every second only
      console.log(new Date());
      timer = null;
      foo();
  }, 1000)
}

foo();
foo();

Since javascript runs synchronous code to completion before processing the next event this is safe.

Johan Gov
  • 1,262
  • 1
  • 13
  • 26
1

My impulse would've been to use clearTimeout to suppress competing timeouts, but I like Johan Gov's answer as well, especially when generalized:

var setOneTimeout = (function() {
  var timer
  return function(f, timeout) {
    if (!timer) {
      timer = setTimeout(function() {
        timer = null
        f()
      }, timeout)
    }
  }
})()

setOneTimeout(function() { console.log('foo') }, 500)
setOneTimeout(function() { console.log('bar') }, 500)
/* outputs "foo", only. */

Or if you'll have multiple categories of timeouts and only want one 'running' timeout in each category:

var setNamedTimeout = (function() {
  var timer = {}
  return function(name, f, timeout) {
    if (!timer[name]) {
      timer[name] = setTimeout(function() {
        timer[name] = null
        f()
      }, timeout)
    }
  }
})()

setNamedTimeout('foo', function() { console.log('foo') }, 500)
setNamedTimeout('bar', function() { console.log('bar') }, 500)
setNamedTimeout('bar', function() { console.log('bar') }, 500)
setNamedTimeout('bar', function() { console.log('bar') }, 500)
setNamedTimeout('bar', function() { console.log('bar') }, 500)
setNamedTimeout('foo', function() { console.log('foo') }, 500)
/* outputs only one instance of "foo" and "bar" */
Julian Fondren
  • 5,459
  • 17
  • 29