开发者

How to stop all timeouts and intervals using javascript? [duplicate]

This question already has answers here: javascript: Clear all timeouts? (13 answers) 开发者_C百科 Closed 5 years ago.

I'm working on an ajax web appliation which contains many running timeouts and intervals. And now I need to clear all running timeouts and intervals sometimes. Is there a simple way to stop everything without need to store every timeout and interval ID and iterate through them and clear them?


Sometimes it's possible to save the timer Id / Handle to clear it later which would be the best solution. So this is a second best. But I wanted to give a better understanding of what's going on. It basically grabs the highest timer id and clears everything less than that. But it's also possible to clear other timers that you do not want to clear!

It is a little hackish, so be warned!

// Set a fake timeout to get the highest timeout id
var highestTimeoutId = setTimeout(";");
for (var i = 0 ; i < highestTimeoutId ; i++) {
    clearTimeout(i); 
}


Updated answer after reading the duplicate I closed this question with -

It works and tested in Chrome on OSX

// run something
var id1 = setInterval(function() { console.log("interval", new Date())}, 1000);
var id2 = setTimeout(function()  { console.log("timeout 1", new Date())}, 2000);
var id3 = setTimeout(function()  { console.log("timeout 2", new Date())}, 5000); // not run
          setTimeout(function()  { console.log("timeout 3", new Date())}, 6000); // not run

// this will kill all intervals and timeouts too in 3 seconds. 
// Change 3000 to anything larger than 10

var killId = setTimeout(function() {
  for (var i = killId; i > 0; i--) clearInterval(i)
}, 3000);

console.log(id1, id2, id3, killId); // the IDs set by the function I used

NOTE: Looked at window objects that had a typeof number - funnily enough IE assigns an 8 digit number, FF a single digit starting with 2


Here is a workaround.

window.timeoutList = new Array();
window.intervalList = new Array();

window.oldSetTimeout = window.setTimeout;
window.oldSetInterval = window.setInterval;
window.oldClearTimeout = window.clearTimeout;
window.oldClearInterval = window.clearInterval;

window.setTimeout = function(code, delay) {
    var retval = window.oldSetTimeout(code, delay);
    window.timeoutList.push(retval);
    return retval;
};
window.clearTimeout = function(id) {
    var ind = window.timeoutList.indexOf(id);
    if(ind >= 0) {
        window.timeoutList.splice(ind, 1);
    }
    var retval = window.oldClearTimeout(id);
    return retval;
};
window.setInterval = function(code, delay) {
    var retval = window.oldSetInterval(code, delay);
    window.intervalList.push(retval);
    return retval;
};
window.clearInterval = function(id) {
    var ind = window.intervalList.indexOf(id);
    if(ind >= 0) {
        window.intervalList.splice(ind, 1);
    }
    var retval = window.oldClearInterval(id);
    return retval;
};
window.clearAllTimeouts = function() {
    for(var i in window.timeoutList) {
        window.oldClearTimeout(window.timeoutList[i]);
    }
    window.timeoutList = new Array();
};
window.clearAllIntervals = function() {
    for(var i in window.intervalList) {
        window.oldClearInterval(window.intervalList[i]);
    }
    window.intervalList = new Array();
};

It works for set/clear timeout/interval functions called after these lines are executed. Try and see it works:

setInterval('console.log(\'a\')', 1000);
setInterval('console.log(\'b\')', 500);
setInterval('console.log(\'c\')', 750);
setTimeout('clearAllIntervals()', 10000);

Proxying does the magic.


var noofTimeOuts = setTimeout('');
for (var i = 0 ; i < noofTimeOuts ; i++) clearTimeout(i);


var max = setTimeout(function(){ /* Empty function */ },1);

        for (var i = 1; i <= max ; i++) {
            window.clearInterval(i);
            window.clearTimeout(i);
            if(window.mozCancelAnimationFrame)window.mozCancelAnimationFrame(i); // Firefox
        }


There's nothing built-in, but it's pretty easy to blast through all currently outstanding deferred execution functions by calling this clearAll() function:

function clearAll() {
  for (var i = setTimeout(function() {}, 0); i > 0; i--) {
    window.clearInterval(i);
    window.clearTimeout(i);
    if (window.cancelAnimationFrame) window.cancelAnimationFrame(i);
  }
}

If you are in charge of the page you run, and can wrap the native deferred execution functions in wrappers that do the house keeping for of course equip each setter function with a corresponding .clearAll() too:

(function(deferFunctions) {
  for (var setter in deferFunctions) (function(setter, clearer) {
    var ids = [];
    var startFn = window[setter];
    var clearFn = window[clearer];

    function clear(id) {
      var index = ids.indexOf(id);
      if (index !== -1) ids.splice(index, 1);
      return clearFn.apply(window, arguments);
    }
    function set() {
      var id = startFn.apply(window, arguments);
      ids.push(id);
      return id;
    }
    set.clearAll = function() { ids.slice(0).forEach(clear); };

    if (startFn && clearFn) {
      window[setter] = set;
      window[clearer] = clear;
    }
  })(setter, deferFunctions[setter]);
})(
{ setTimeout: 'clearTimeout'
, setInterval: 'clearInterval'
, requestAnimationFrame: 'cancelAnimationFrame'
});

To try that it works, you could then try doing this, for instance, which will remain silent, as none of the callbacks end up firing before they're cancelled again:

// Some example timers of all types:
requestAnimationFrame(console.error);
setInterval(console.info, 1000, 'interval');
setTimeout(alert, 0, 'timeout');

// Now you can clear all deferred functions
// by execution type, whenever you want to:
window.setTimeout.clearAll();
window.setInterval.clearAll();
window.requestAnimationFrame.clearAll();


A little hack added to Gokhan Ozturk's answer

If you are using third party libraries which uses Timeouts and Intervals then they will also be cleared, so I added one parameter to notify function that this interval is to be push'ed or not to array.

window.setTimeout = function(code, delay, toBeAdded) {
    var retval = window.oldSetTimeout(code, delay);
    var toBeAdded = toBeAdded || false;
    if(toBeAdded) {
        window.timeoutList.push(retval);
    }
    return retval;
};
... // likewise for all functions.


You might be better off creating a scheduler. Take a look at this approach by Nader Zeid:

https://www.onsip.com/blog/avoiding-javascript-settimeout-and-setinterval-problems

It's an approach that help create some determinacy (because "the time interval argument of each of those functions really only establishes that the given function will execute after at least that amount of time. So a timed event can miss its target by literally any amount of time.").

Specifically, to the question you raise here, you can easily add and remove functions from the queue. While this response is long after the question was raised, hopefully it's helpful to any who find themselves struggling with Timeouts and Intervals.


You cannot clear any timeouts and intervals you don't know about.

You'd need something like getTimeoutList which isn't in the DOM3 spec, or even planned, AFAIK.


The previous proxying trick is nice, but if you have a lot of timeouts and intervals, I would not fill the arrays with consecutive numbers [1,2,3....], but with intervals. For example, instead of having [1,2,3,7,8,9], you would have maybe something like ['1-3','7-9'] or [[1,3],[7,9]], as a memory optimization. Of course this trick is only suited if you have a lot of timeouts and intervals and also if you would not stop arbitrary intervals that often.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜