javascript:清除所有超时?


99

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

任何跨浏览器解决方案都是受欢迎的。



6
杜德(Dude),这个问题来自3年前,并且有很好的答案。无需为此烦恼。
marcio

我搜索了一下,找到了两者。您的年龄较大,因此我认为将两个问题简化为一个问题是一项很好的整理工作。我的只是一票。还有更多人需要投票关闭,重复的链接可能会对其他人有所帮助。
2015年

2
@Bernard Hofmann我不确定,如果这个答案更好,它是否可以作为重复问题。从2010年开始,关于该答案的公认答案是“否”。
RoboticRenaissance

Answers:


148

它们不在window对象中,但是具有id,它们(afaik)是连续的整数。

因此,您可以像这样清除所有超时:

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

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

1
这是规范的一部分,还是取决于实现?
蒂洪

7
它不必从1开始。HTML5规范说:“让句柄是用户代理定义的整数,该整数大于零,它将标识此调用要设置的超时。” 这为句柄留出了可以是任何正整数(包括非连续整数和非小整数)的空间。
Mike Samuel

3
这非常聪明,但是OP可能应该询问是否有更好的解决方案来跟踪活动计时器。
杰森·哈维格

3
这不是一个无限循环吗?并非所有浏览器都将if(0)呈现为false。
特拉维斯J

2
因为我问过如何清除所有超时,所以我接受了这个答案。非常聪明的解决方案。
marcio 2012年

79

我认为最简单的方法是将所有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]);
}

14
这具有仅清除设置的内容的优点(或潜在的缺点,我想),因此您不会无意间破坏外部代码。
蒂洪

1
+1,不会清除所有超时,但是是一次清除特定超时组的好解决方案
marcio 2012年

1
这是最好的解决方案,因为它不会破坏外部代码,但是由于我问如何清除所有超时,我最终接受了@ Pumbaa80答案:)
marcio

2
@marcioAlmada很奇怪,但是很高兴看到您在2.5年后再次对此发表评论:)
Michael

6
也许我想清除进入我无法控制的网页时的所有超时和间隔,因为它们有一个烦人的弹出广告,直到我的adblocker运行之后才开始。
RoboticRenaissance

12

对于Pumbaa80的答案,我还有一个补充,它可能对为旧IE开发的人有用。

是的,所有主要的浏览器都将超时ID实现为连续的整数(规范不需要)。整个浏览器之间的起始编号不同。似乎Opera,Safari,Chrome和IE> 8从1开始,基于Gecko的浏览器的超时ID从2开始,而IE <= 8从某个随机数开始,这些随机数被魔术地保存在选项卡刷新中。你可以自己发现

这说明在IE <= 8中,该while (lastTimeoutId--)循环可能会运行8 位数次,并显示“ 此页面上的脚本导致Internet Explorer运行缓慢 ”消息。因此,如果您无法保存所有的超时ID或不想覆盖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);
    };
});

然后清除所有可能由外来代码设置的未决超时,您需要进行多次


再加上一个用于澄清一些更详细的信息。
桑杰2015年

8

如何将超时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
    }
};

3

您必须重写该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();
  }
}

3

要清除所有超时他们必须“捕获” 第一

将以下代码放在任何其他脚本之前,它将为原始setTimeout&创建包装函数clearTimeout

clearTimeouts方法将添加到window对象,这将允许清除所有(待处理)超时(Gist链接)。

其他答案缺乏对可能收到的论点的完全支持。 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);

2

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

似乎浏览器可能对这两者使用相同的ID池,但是从对clearTimeout和clearInterval是否相同的一些答案中得出?,尚不清楚依靠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 watcher,因此在清除所有超时和时间间隔时无法进行热重装。我认为其他热重载监视程序的框架也是如此(例如(角度,反应,余烬等))
Michail Michailidis

1

我将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
        }
    }

0

使用全局超时,您的所有其他函数都将从中导出超时。尽管它将为您的代码添加一些抽象,但这将使所有内容运行起来更快,并且更易于管理。


我不完全了解你。您是要扩展set_timeout全局功能的行为?你能举个例子代码吗?
marcio 2012年

1
我只是说您有一个全局超时,每50毫秒运行一次。然后,需要计时元素的所有其他功能将从全局超时中获取它。Google出于效率考虑而改用此方法,尽管我再也找不到引用它的文章了。
特拉维斯J

0

我们刚刚发布了解决此确切问题的软件包。

npm install time-events-manager

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


0

这很晚了...但是:

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

const highestId = window.setTimeout(() => {
  for (let i = highestId; i >= 0; i--) {
    window.clearInterval(i);
  }
}, 0);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.