如何防止 clearInterval 破坏 setTimeout

How to prevent clearInterval from breaking setTimeout

我是第三方 javascript 开发人员,我的一个客户在他们的页面上有以下代码,重复 运行:

for (var i = 1; i < 99999; i++) {
    window.clearInterval(i);
}

这当然会打破我的 setInterval 循环。我想我可以通过使用 setTimeout 来解决这个问题,如果某些条件尚未满足,它会创建另一个 setTimeout。令我惊讶的是,上面的 clearInterval 代码 打破了我的超时。

您甚至可以在不创建 setTimeout 循环的情况下观察到这种行为,而只是一个单独的计时器(我将其包装在一些额外的代码中以使其远离 window):

var example = (function(){
  return {
    foo: setTimeout(function(){
      console.log('bar');
    }, 5000)
  };
}());

for (var i = 1; i < 99999; i++) {
    window.clearInterval(i);
}

我唯一能想到的就是覆盖内置的 clearInterval 以不专门清除我的计时器,但这对我来说似乎非常错误和肮脏。

var originalClearInterval = window.clearInterval;

var exampleLoop = setInterval(function() {
  console.log('loop running');
  if(typeof window.stopRunning !== 'undefined' && window.stopRunning === true) {
    window.clearInterval = originalClearInterval;
    clearInterval(exampleLoop);
    console.log('loop finished');
  }
}, 50);

window.clearInterval = function(timerId) {
  if(timerId !== exampleLoop) {
    originalClearInterval.apply(this, arguments);
  }
}

所以有办法:将您的 setTimeout 调用放在一个孤立的地方,例如 WebWorkerIFrame,然后提供一些事件来监听。

我知道这只是一个 setTimeout 的 hack,但比替换 clearInterval 更好。

我能想到的唯一方法就是玩肮脏的游戏 - 重新定义 window.clearInterval,忽略超时 ID 的清除:

// create an array to store timeout IDs to ignore.
window.ignoreTimeoutIds = [];

// store original clearInterval function as another property
window.clearInterval2 = window.clearInterval;

// redefine clearInterval to not clear if it is one of your timeoutIds
window.clearInterval = function(intervalId) {
  if (window.ignoreTimeoutIds.indexOf(intervalId) > -1)
    console.log('not clearing 1'); // for demo purposes
  else
    window.clearInterval2(intervalId);
};


(function() {

  //set the timeout and get its  ID
  var timeoutId = setTimeout(function() {
    console.log('bar');
    // don't forget to remove the timeoutId from the ignore list
    window.ignoreTimeoutIds.splice(window.ignoreTimeoutIds.indexOf(timeoutId))
  }, 5000);

  // add the timeoutID to the ignore list
  window.ignoreTimeoutIds.push(timeoutId);
}());

for (var i = 1; i < 99999; i++) {
  window.clearInterval(i);
}

如果您希望该部分更整洁,您还可以为 setTimeout() 创建一个包装器来处理数组中的添加和删除。

知道为什么他们运行那段丑陋的代码会很有趣...

无论如何,你的想法是写一些更丑陋的东西是朝着正确方向迈出的一步,但你可以在不触及它们自己的功能的情况下将丑陋程度提高一个档次(你是第三方,请记住 - 我很惊讶您甚至有权 查看 他们的代码)。您甚至不需要额外的身份管理工作:

function setBulletproofTimeout( code, delay ) {

    var minId = 99999;
    var id = 0;
    var myIntervals = [];
    for ( var i = 0; i<=minId; i++) {
       id = window.setTimeout(code, delay);
       if( id >= minId ) {
            // that's the One, kill the others
            myIntervals.forEach( function( e ) { window.clearInterval( e ); } );
            return id;
       }
       else {
            myIntervals.push( id );
       }
    }
}