javascript:清除所有超时?

Posted

技术标签:

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

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

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

【问题讨论】:

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

【讨论】:

以上是关于javascript:清除所有超时?的主要内容,如果未能解决你的问题,请参考以下文章

使用JavaScript清除Microsoft Word粘贴文本

Redis官方教程 Expire超时

javascript的垃圾回收机制和内存管理

查看javascript中的所有超时/间隔?

使用 JavaScript 清除所有 cookie

PHP Curl Timeout 导致 Javascript 客户端崩溃