【问题标题】:javascript: Clear all timeouts?javascript:清除所有超时?
【发布时间】:2012-02-10 05:22:47
【问题描述】:

有没有办法清除给定窗口的所有超时?我想超时存储在 window 对象中的某处,但无法确认。

欢迎任何跨浏览器解决方案。

【问题讨论】:

  • 老兄,这个问题是 3 年前的问题,里面有很好的答案。没必要搞砸。
  • 我搜索了这个并找到了两者。你的问题比较大,所以我认为将这两个问题减少到一个是很好的家务。我的只有一票;更多的人需要投票才能关闭,重复的链接可能会帮助其他人。
  • @Bernard Hofmann 我不确定如果这个问题得到了更好的答案,它是否算作重复问题。从 2010 年开始,人们接受的答案是“否”。
  • 在任何合理大小的系统中执行此操作都是个坏主意。你可以在系统中完全不相关的部分杀死你不知道的任务。

标签: javascript timeout


【解决方案1】:

它们不在窗口对象中,但它们有 ids,它们 (afaik) 是连续的整数。

所以你可以像这样清除所有超时:

var id = window.setTimeout(function() {}, 0);

while (id--) {
    window.clearTimeout(id); // will do nothing if no timeout with id is present
}

【讨论】:

  • 这是规范的一部分,还是依赖于实现?
  • 它不需要从 1 开始。HTML5 规范说“让句柄是一个大于零的用户代理定义的整数,它将标识此调用设置的超时。”这为句柄留出了空间,可以是任何正整数,包括非连续和非小整数。
  • 这很聪明,但 OP 应该会问是否有更好的解决方案来跟踪活动计时器。
  • 这不是无限循环吗?并非所有浏览器都将 if(0) 呈现为 false。
  • 既然我问过如何清除所有超时,我接受了这个答案。非常聪明的解决方案。
【解决方案2】:

我认为完成此操作的最简单方法是将所有 setTimeout 标识符存储在一个数组中,您可以在其中轻松迭代到所有 clearTimeout()

var timeouts = [];
timeouts.push(setTimeout(function(){alert(1);}, 200));
timeouts.push(setTimeout(function(){alert(2);}, 300));
timeouts.push(setTimeout(function(){alert(3);}, 400));

for (var i=0; i<timeouts.length; i++) {
  clearTimeout(timeouts[i]);
}

【讨论】:

  • 这有好处(或潜在的缺点,我猜)只清除 设置的那些,所以你不会无意中破坏外部代码。
  • +1,不会清除所有超时,但是是一次清除特定组超时的好方法
  • 这是最好的解决方案,因为它不会破坏外部代码,但由于我问过如何清除所有超时,我最终接受了@Pumbaa80 答案:)
  • @marcioAlmada 很奇怪,但很高兴看到你在 2.5 年后再次对此发表评论:)
  • 也许我想在进入我无法控制的网页时清除所有超时和间隔,因为它们有一个烦人的弹出广告,直到我的广告拦截器运行后才会开始。跨度>
【解决方案3】:

我对@9​​87654321@ 有一个补充,它可能对为旧 IE 开发的人有用。

是的,所有主流浏览器都将超时 id 实现为连续整数(即not required by specification)。尽管起始编号因浏览器而异。似乎 Opera、Safari、Chrome 和 IE > 8 从 1 开始超时 ID,基于 Gecko 的浏览器从 2 开始,IE discover it yourself。

这意味着在 IE while (lastTimeoutId--) 循环可能会运行超过 8 位,并显示“此页面上的脚本导致 Internet Explorer 运行缓慢”消息。因此,如果您不能save all you timeout id's 或不想override window.setTimeout,您可以考虑在页面上保存第一个超时 id 并在此之前清除超时。

在页面加载早期执行代码:

var clearAllTimeouts = (function () {
    var noop = function () {},
        firstId = window.setTimeout(noop, 0);
    return function () {
        var lastId = window.setTimeout(noop, 0);
        console.log('Removing', lastId - firstId, 'timeout handlers');
        while (firstId != lastId)
            window.clearTimeout(++firstId);
    };
});

然后清除所有可能由外部代码设置的所有未决超时

【讨论】:

  • 加一个用于澄清一些更详细的信息。
【解决方案4】:

这已经很晚了……但是:

基本上,setTimeout/setInterval ID 的顺序是连续的,所以只需创建一个虚拟超时函数来获取最高 ID,然后清除所有低于该 ID 的间隔。

const highestId = window.setTimeout(() => {
  for (let i = highestId; i >= 0; i--) {
    window.clearInterval(i);
  }
}, 0);

【讨论】:

  • 这对我来说是最好的解决方案!!谢谢你,查里
  • 在 for 循环内,clearInterval 还是 clearTimeout?
  • 任何一个都有效,因为它们基本上做同样的事情
  • 不错的解决方案,但请注意,与其他一些答案不同,这不会立即清除超时;它将等到下一个事件循环。
  • 太棒了!这正是我一直在寻找的。 +1
【解决方案5】:

如何将超时 id 存储在全局数组中,并定义一个方法来将函数调用委托给窗口。

GLOBAL={
    timeouts : [],//global timeout id arrays
    setTimeout : function(code,number){
        this.timeouts.push(setTimeout(code,number));
    },
    clearAllTimeout :function(){
        for (var i=0; i<this.timeouts.length; i++) {
            window.clearTimeout(this.timeouts[i]); // clear all the timeouts
        }
        this.timeouts= [];//empty the id array
    }
};

【讨论】:

    【解决方案6】:

    你必须重写window.setTimeout方法并保存它的超时ID。

    const timeouts = [];
    const originalTimeoutFn = window.setTimeout;
    
    window.setTimeout = function(fun, delay) { //this is over-writing the original method
      const t = originalTimeoutFn(fn, delay);
      timeouts.push(t);
    }
    
    function clearTimeouts(){
      while(timeouts.length){
        clearTimeout(timeouts.pop();
      }
    }
    

    【讨论】:

      【解决方案7】:

      要清除所有超时,必须先“捕获”它们

      将以下代码放在任何其他脚本之前,它将为原始setTimeoutclearTimeout 创建一个包装函数。

      一个新的clearTimeouts 方法将添加到window 对象,这将允许清除所有(待定)超时(Gist link)。

      其他答案缺乏完整支持setTimeout可能收到的可能参数

      // isolated layer wrapper (for the local variables)
      (function(_W){
      
      var cache = [],                // will store all timeouts IDs
          _set = _W.setTimeout,      // save original reference
          _clear = _W.clearTimeout  // save original reference
      
      // Wrap original setTimeout with a function 
      _W.setTimeout = function( CB, duration, arg ){
          // also, wrap the callback, so the cache reference will be removed 
          // when the timeout has reached (fired the callback)
          var id = _set(function(){
              CB.apply(null, arguments)
              removeCacheItem(id)
          }, duration || 0, arg)
      
          cache.push( id ) // store reference in the cache array
      
          // id reference must be returned to be able to clear it 
          return id
      }
      
      // Wrap original clearTimeout with a function 
      _W.clearTimeout = function( id ){
          _clear(id)
          removeCacheItem(id)
      }
      
      // Add a custom function named "clearTimeouts" to the "window" object
      _W.clearTimeouts = function(){
          console.log("Clearing " + cache.length + " timeouts")
          cache.forEach(n => _clear(n))
          cache.length = []
      }
      
      // removes a specific id from the cache array 
      function removeCacheItem( id ){
          var idx = cache.indexOf(id)
      
          if( idx > -1 )
              cache = cache.filter(n => n != id )
      }
      
      })(window);
      
      

      【讨论】:

      • 这是最正确最完整的答案。
      【解决方案8】:

      为了完整起见,我想发布一个涵盖setTimeoutsetInterval 的通用解决方案。

      似乎浏览器可能对两者使用相同的 ID 池,但从对 Are clearTimeout and clearInterval the same? 的一些答案来看,尚不清楚依赖 clearTimeoutclearInterval 执行相同功能或仅工作是否安全关于它们各自的计时器类型。

      因此,当目标是终止所有超时和间隔时,这里的实现可能会在无法测试所有实现时稍微更具防御性:

      function clearAll(windowObject) {
        var id = Math.max(
          windowObject.setInterval(noop, 1000),
          windowObject.setTimeout(noop, 1000)
        );
      
        while (id--) {
          windowObject.clearTimeout(id);
          windowObject.clearInterval(id);
        }
      
        function noop(){}
      }
      

      您可以使用它来清除当前窗口中的所有计时器:

      clearAll(window);
      

      或者您可以使用它来清除iframe 中的所有计时器:

      clearAll(document.querySelector("iframe").contentWindow);
      

      【讨论】:

      • 请记住,这种方法会破坏 vue-cli-service 观察程序,因此您在清除所有超时和时间间隔时无法进行热重载。我认为对于其他框架的热重载观察者来说也是一样的,比如(angular、react、ember 等)
      【解决方案9】:

      我使用 Vue 和 Typescript。

          private setTimeoutN;
          private setTimeoutS = [];
      
          public myTimeoutStart() {
      
              this.myTimeoutStop();//stop All my timeouts
      
              this.setTimeoutN = window.setTimeout( () => {
                  console.log('setTimeout');
              }, 2000);
      
              this.setTimeoutS.push(this.setTimeoutN)//add THIS timeout ID in array
      
          }
      
          public myTimeoutStop() {
      
              if( this.setTimeoutS.length > 0 ) {
                  for (let id in this.setTimeoutS) {
                      console.log(this.setTimeoutS[id]);
                      clearTimeout(this.setTimeoutS[id]);
                  }
                  this.setTimeoutS = [];//clear IDs array
              }
          }
      

      【讨论】:

        【解决方案10】:

        使用全局超时,您的所有其他函数都从中派生计时。这将使一切运行得更快,更易于管理,尽管它会为您的代码添加一些抽象。

        【讨论】:

        • 我不完全理解你。您的意思是扩展set_timeout 全局函数的行为?能给个示例代码吗?
        • 我的意思是你有一个全局超时,每 50 毫秒运行一次。然后,需要计时元素的所有其他功能将从全局超时中获取它。谷歌为了提高效率而改用这个,虽然我再也找不到引用它的文章了。
        【解决方案11】:

        我们刚刚发布了一个解决这个确切问题的包。

        npm install time-events-manager

        这样,您可以通过timeoutCollectionintervalCollection 对象查看所有超时和间隔。 还有一个removeAll 函数可以清除集合和浏览器中的所有超时/间隔。

        【讨论】:

          【解决方案12】:

          函数f(...){}timeout定义后的setTimeout内可以附加参数。

          例如:$setTimeout(function(a, b){ run(a); run(b); }, 100, a, b); )

          ...args 解决了这个问题。

              var $timeouts = new Array();
          
              function $setTimeout(...args) 
              {
                var t = window.setTimeout(...args);
                $timeouts.push(t);
                return t;
              }
          
              function $clearTimeout(id) 
              {
                  if( $timeouts.indexOf(id) > -1 )
                      $timeouts = $timeouts.filter(n => n != id )
          
                  window.clearTimeout(id);
              }
          
          
              function $clearTimeouts()
              {
                  while($timeouts.length)
                     window.clearTimeout($timeouts.pop());
              }
          

          对于旧浏览器,您需要使用其他方法来传递参数并从数组 $timeouts 中删除值。

          var $timeouts = new Array();
          
          function $setTimeout() 
          {
            var t = window.setTimeout.apply( this, arguments );
            $timeouts.push(t);
            return t;
          }
          
          function $clearTimeout(id) 
          {
              var index = $timeouts.indexOf(id);
          
              if (index > -1) {
                 $timeouts.splice(index, 1);
              }
          
              window.clearTimeout(id);
          }
          
          
          function $clearTimeouts()
          {
              while($timeouts.length)
                 window.clearTimeout($timeouts.pop());
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-12-29
            • 1970-01-01
            • 1970-01-01
            • 2013-10-09
            • 1970-01-01
            • 1970-01-01
            • 2010-09-15
            相关资源
            最近更新 更多