javascript: Clear all timeouts?-ThrowExceptions

Exception or error:

Is there a way to clear all time outs from a given window? I suppose the timeouts are stored somewhere in the window object but couldn’t confirm that.

Any cross browser solution is welcome.

How to solve:

They are not in the window object, but they have ids, which (afaik) are consecutive integers.

So you may clear all timeouts like so:

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

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

###

I think the easiest way to accomplish this would be to store all the setTimeout identifiers in one array, where you can easily iterate to clearTimeout() on all of them.

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]);
}

###

I have an addition to Pumbaa80’s answer that might be useful for someone developing for old IEs.

Yes, all major browsers implement timeout ids as consecutive integers (which is not required by specification). Althrough the starting number differs form browser to browser. It seems that Opera, Safari, Chrome and IE > 8 starts timeout ids from 1, Gecko-based browsers from 2 and IE <= 8 from some random number that is magically saved across tab refresh. You can discover it yourself.

All that meens that in IE <=8 the while (lastTimeoutId--) cycle may run over 8digits times and show the “A script on this page is causing Internet Explorer to run slowly” message. So if you can not save all you timeout id’s or don’t want to override window.setTimeout you may consider saving the first timeout id on a page and clearing timeouts until it.

Execute the code on early page load:

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

And then clear all pending timeouts that probably was set by foreign code so many times you want

###

How about store the timeout ids in a global array, and define a method to delegate the function call to the window’s.

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
    }
};

###

You have to rewrite the window.setTimeout method and save its timeout 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();
  }
}

###

Without changing any existing code, you can place the this code before any other script and it will create a wrapper function for the original setTimeout & clearTimeout and also add a new one clearTimeouts methods, which will allow clearing all the (pending) timeouts (Gist link)

// 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 ){
    // also, wrap the callback, so the cache referece will be removed 
    // when the timerout has reached (fired the callback)
    var id = _set(function(){
        CB();
        removeCacheItem(id);
    }, duration || 0);

    cache.push( id ); // store reference in the cache array

    // id must be returned to the user could save it and clear it if they choose to
    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(){
    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);

###

For completeness, I wanted to post a general solution that covers both setTimeout and setInterval.

It seems browsers might use the same pool of IDs for both, but from some of the answers to Are clearTimeout and clearInterval the same?, it’s not clear whether it’s safe to rely on clearTimeout and clearInterval performing the same function or only working on their respective timer types.

Therefore, when the goal is to kill all timeouts and intervals, here’s an implementation that might be slightly more defensive across implementations when unable to test all of them:

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(){}
}

You can use it to clear all timers in the current window:

clearAll(window);

Or you can use it to clear all timers in an iframe:

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

###

I use Vue with 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
        }
    }

###

Use a global timeout which all of your other functions derive timing from. This will make everything run faster, and be easier to manage, although it will add some abstraction to your code.

###

We’ve just published a package solving this exact issue.

npm install time-events-manager

With that, you can view all timeouts and intervals via timeoutCollection & intervalCollection objects.
There’s also a removeAll function which clears all timeouts/intervals both from the collection and the browser.

Leave a Reply

Your email address will not be published. Required fields are marked *