115

I'm writing an application that utilizes JavaScript timeouts and intervals to update the page. Is there a way to see how many intervals are setup? I want to make sure that I'm not accidentally going to kill the browser by having hundreds of intervals setup.

Is this even an issue?

Omar Kooheji
  • 54,530
  • 68
  • 182
  • 238

7 Answers7

100

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.

Alessio Cantarella
  • 5,077
  • 3
  • 27
  • 34
Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
  • 10
    I used this in some code today, but I needed `activeTimers` to decrement when `clearTimeout` was *not* called. That's easily accomplished by replacing the second line of `window.setTimeout` with this: `return window.originalSetTimeout(function() {func(); activeTimers--;},delay);` – Rick Hitchcock Jul 20 '15 at 22:07
  • 3
    This answer will not be able to work any more since DOM-related JavaScript functions will be 'immutable'. – John Greene Jul 06 '16 at 14:55
33

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

Timers Chrome Devtool extension

setInterval-sniffer

NVI
  • 14,907
  • 16
  • 65
  • 104
14

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.
A1rPun
  • 16,287
  • 7
  • 57
  • 90
  • Is it possible to get name of all running `SetIntervals`? For example `var timer = setInterval(function () { }` I need *timer* instead of count of running intervals. – Yogesh Patel Sep 06 '17 at 05:38
  • Not that I know of, I'd suggest though a global search with the keyword "setInterval" and/or "setTimeout" – Neithan Max Mar 16 '18 at 10:52
11

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);
};
crv
  • 3,024
  • 4
  • 27
  • 31
5

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

Ziv polack
  • 59
  • 1
  • 4
  • 6
    I think OP and most people were looking for something to either type in the browser's console as the first PoC and maybe later in an extension. How would one go about putting that in the console from the information you gave? – Neithan Max Mar 16 '18 at 10:48
1

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).

Alessio Cantarella
  • 5,077
  • 3
  • 27
  • 34
akinuri
  • 10,690
  • 10
  • 65
  • 102
  • Be careful using integers as object indexes. Its best to convert integers to strings before using as a key on an object in JavaScript. This way you don't collide with JavaScript's intrinsic index logic using integers. This used to be a problem way back in the day. Maybe its not any longer though. – Timothy C. Quinn Jul 10 '21 at 00:16
0

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

Timothy C. Quinn
  • 3,739
  • 1
  • 35
  • 47