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

我正在编写一个应用程序,利用 JavaScript 超时和间隔来更新页面。有没有办法看看有多少间隔设置?我想确保我不会因为设置了数百个间隔而意外地关闭浏览器。

这有什么问题吗?

101190 次浏览

I don't think there is a way to enumerate active timers, but you could override window.setTimeout and window.clearTimeout and replace them with your own implementations which do some tracking and then call the originals.

window.originalSetTimeout = window.setTimeout;
window.originalClearTimeout = window.clearTimeout;
window.activeTimers = 0;


window.setTimeout = function(func, delay) {
window.activeTimers++;
return window.originalSetTimeout(func, delay);
};


window.clearTimeout = function(timerID) {
window.activeTimers--;
window.originalClearTimeout(timerID);
};

Of course, you might not always call clearTimeout, but this would at least give you some way to track what is happening at runtime.

Seeing as Paul has only covered setTimeout I thought I would share a counter for setInterval/clearInterval.

window.originalSetInterval = window.setInterval;
window.originalClearInterval = window.clearInterval;
window.activeIntervals = 0;
window.setInterval = function (func, delay)
{
if(func && delay){
window.activeIntervals++;
}
return window.originalSetInterval(func,delay);
};
window.clearInterval = function (intervalId)
{
// JQuery sometimes hands in true which doesn't count
if(intervalId !== true){
window.activeIntervals--;
}
return window.originalClearInterval(intervalId);
};

I made a Chrome DevTools extension that shows all intervals. Cleared ones are greyed out.

Timers Chrome Devtool extension

setInterval-sniffer

Instead of just have a count of timers, here is an implementation which stores all timerid's into an array. It only shows active timers while the accepted answer only counts calls to setTimeout & clearTimeout.

(function(w) {
var oldST = w.setTimeout;
var oldSI = w.setInterval;
var oldCI = w.clearInterval;
var timers = [];
w.timers = timers;
w.setTimeout = function(fn, delay) {
var id = oldST(function() {
fn && fn();
removeTimer(id);
}, delay);
timers.push(id);
return id;
};
w.setInterval = function(fn, delay) {
var id = oldSI(fn, delay);
timers.push(id);
return id;
};
w.clearInterval = function(id) {
oldCI(id);
removeTimer(id);
};
w.clearTimeout = w.clearInterval;


function removeTimer(id) {
var index = timers.indexOf(id);
if (index >= 0)
timers.splice(index, 1);
}
}(window));

This is how you can get the count of active timers on the page:

timers.length;

This is how you can remove all active timers:

for(var i = timers.length; i--;)
clearInterval(timers[i]);

Known limitations:

  • You can only pass a function (not a string) to setTimeout with this monkey patch.
  • The function assumes clearInterval and clearTimeout do the same, which they do but it could change in the future.

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

npm install time-events-manager

With that, you can view and manage them via timeoutCollection object (and javascript's intervals viaintervalCollection object).

timeoutCollection.getScheduled(); timeoutCollection.getCompleted(); timeoutCollection.getAll();

I just needed something like this and this is what I've put together:

window.setInterval = function (window, setInterval) {
if (!window.timers) {
window.timers = {};
}
if (!window.timers.intervals) {
window.timers.intervals = {};
}
if (!window.timers.intervals.active) {
window.timers.intervals.active = {};
}
return function (func, interval) {
var id = setInterval(func, interval);
window.timers.intervals.active[id] = func;
return id;
}
}(window, window.setInterval);


window.clearInterval = function (window, clearInterval) {
if (!window.timers) {
window.timers = {};
}
if (!window.timers.intervals) {
window.timers.intervals = {};
}
if (!window.timers.intervals.inactive) {
window.timers.intervals.inactive = {};
}
return function (id) {
if (window.timers.intervals.active && window.timers.intervals.active[id]) {
window.timers.intervals.inactive[id] = window.timers.intervals.active[id];
clearInterval(id);
delete window.timers.intervals.active[id];
}
}
}(window, window.clearInterval);

This records the interval ids along with their functions, and also keeps track of their status (active/inactive).

Based on @Alessio's answer. Below is my version. Has a bit more functionality for logging and inspection.

Here is some boilerplate that you can alter to utilize your own frameworks:

var s$ = function (s){return new String(s)}
var _w=window
_w.q$ = {
getMachineTimeMS: function(){
var d = new Date(), ms = d.getMilliseconds()
var a = [d.getHours(), d.getMinutes(), d.getSeconds(), '-', ms<10?'00' + s$(ms):ms<100?'0'+s$(ms):ms]
return a.join('')
}
,getCaller: function(opts){
return "(implement this)"
}
}

Here is the main code:

_w.setTimeout = function (orig_setTimeout) {
var t=(_w._Timers = _w._Timers||{})
var d=(t.Timeouts = t.Timeouts||{})
d.Active = d.Active||{}
t.z_to_id_idx = t.z_to_id_idx||{}
return function (h, n) {
var t = _w._Timers, d = t.Timeouts
var id = orig_setTimeout(h, n), ts = q$.getMachineTimeMS()
var c = q$.getCaller({depth:2})
t.z_to_id_idx[s$(id)] = d.Active[ts] = {sts: ts, id: id, h: h, n: n, scaller: c}
return id;
}
}(_w.setTimeout);


_w.clearTimeout = function (orig_clearTimeout) {
var t=_w._Timers, d = t.Timeouts
d.Inactive = d.Inactive||{}
return function new_clearTimeout(id) {
var t = _w._Timers, d = t.Timeouts, sId = s$(id)
if (!d.Active || !sId in t.z_to_id_idx) return
var r = t.z_to_id_idx[sId]
r.ccaller = q$.getCaller({depth:2})
r.cts = q$.getMachineTimeMS()
d.Inactive[r.ts] = r;
orig_clearTimeout(r.id);
delete d.Active[r.ts]
delete t.z_to_id_idx[sId]
}
}(_w.clearTimeout);


_w.setInterval = function (orig_setInterval) {
var t=(_w._Timers = _w._Timers||{})
var d=(t.Intervals = t.Intervals||{})
d.Active = d.Active||{}
t.z_in_id_idx = t.z_in_id_idx||{}
return function (h, n) {
var t = _w._Timers, d = t.Intervals
var id = orig_setInterval(h, n), ts = q$.getMachineTimeMS()
var c = q$.getCaller({depth:2})
t.z_in_id_idx[s$(id)] = d.Active[ts] = {sts: ts, id: id, h: h, n: n, scaller: c}
return id;
}
}(_w.setInterval);


_w.clearInterval = function (orig_clearInterval) {
var t=_w._Timers, d = t.Intervals
d.Inactive = d.Inactive||{}
return function new_clearInterval(id) {
var t = _w._Timers, d = t.Intervals, sId = s$(id)
if (!d.Active || !sId in t.z_in_id_idx) return
var r = t.z_in_id_idx[sId]
r.ccaller = q$.getCaller({depth:2})
r.cts = q$.getMachineTimeMS()
d.Inactive[r.ts] = r;
orig_clearInterval(r.id);
delete d.Active[r.ts]
delete t.z_in_id_idx[sId]
}
}(_w.clearInterval);

Usage example:

id = setTimeout(()=>{console.log("CALLED")}, 10000)
clearTimeout(id)
setInterval(()=>{console.log("CALLED")}, 1000)


console.table(_w._Timers.Timeouts.Inactive)

The console.table will output a nicely formatted and inspectable table in the JavaScript Console