我怎样才能确保我只有一个递归的setTimeout链一次运行?

时间:2015-10-16 17:47:22

标签: javascript recursion google-chrome-extension settimeout

我正在制作个人使用的chrome扩展程序,它将以递归方式调用setTimeout。我想确保在任何情况下此扩展都不会意外地产生多个setTimeouts链。

我已经做到这一点,当我点击浏览器操作时,它会调用clearTimeout。但是,我担心当我重新加载扩展时,旧的超时链可以继续吗?并且可能还有其他我不想的场景。是否有一种经过验证的方法来防止意外创建多个超时链?

看起来无法枚举有效的javascript计时器:Viewing all the timouts/intervals in javascript?

2 个答案:

答案 0 :(得分:1)

我之前解决过类似的案例:

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();

由于javascript在处理下一个事件之前将同步代码运行完成,因此这是安全的。

答案 1 :(得分:1)

我的冲动一直是使用clearTimeout来抑制竞争超时,但我也喜欢Johan Gov的回答,特别是在推广时:

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. */

或者,如果您有多个类别的超时,并且只希望每个类别中有一个“正在运行”超时:

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" */