Is there a way to stop a setInterval without its timerId? [duplicate] - javascript

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?

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.

I made a Chrome DevTools extension that shows all intervals. Cleared ones are greyed out.
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.

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

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

Related

Evaluating JavaScript expression with a worker

I need to evaluate JavaScript expressions, in a browser, Chrome. To make it safe, I use a Blob and a Worker running my evaluator, until it posts back the result of a timeout cancels the wait. This is working fine. I also need to support an environment for my JavaScript. I do this as below:
function evalWorker () {
let postResponse = function(expr, ...) {
let presets = `var EnvObject = {};
EnvObject.platform = "Chrome";
EnvObject.pasteboard = "${clipboard}";
EnvObject.baseDate = new Date();
...
EnvObject._output = "";
EnvObject.appendOutput = (str) => {EnvObject._output += str; };
`
postMessage(eval(presets + expr));
};
onmessage = function(e) {
postResponse(e.data['expression'], e.data['clipboard'], ...);
}
}
My problem is that if _output is not empty, I need to return that - _output instead of the evaluated expression, as in
EnvObject.appendOutput('hello');
var a = 0;
++a;
Should return hello; while without appendOutput, it should return 1.
How would I go about something like this?
#Bergi had the right idea with pushing the scope out. The below works.
function evalWorker () {
let postResponse = function(expr, TextExpander) {
let result = eval(expr);
if (EnvObject._output && EnvObject._output.length) {
postMessage(EnvObject._output);
} else {
postMessage(result);
}
};
onmessage = function(e) {
var EnvObject = {};
EnvObject.platform = "Chrome";
EnvObject.pasteboardText = e.data['clipboard'];
...
EnvObject._output = "";
EnvObject.appendOutput = function(str) {EnvObject._output += str; };
postResponse(e.data['expression'], EnvObject);
}
}

A Javascript function which creates an object which calls the function itself

I am trying to make an angular service that returns a new object.
That's fine and good and works. new MakeRoll() creates an instance. But self.add, near the end also calls new MakeRoll() and that doesn't create an instance when I call add like I think it should.
I'm probably doing this all wrong but I haven't been able to figure it out.
var services = angular.module('services', []);
services.factory('Roll', [function() {
var MakeRoll = function () {
var self = {};
self.rolls = [];
self.add = function(number, sizeOfDice, add) {
var newRoll = {};
newRoll.number = number || 1;
newRoll.sizeOfDice = sizeOfDice || 6;
newRoll.add = add || 0;
newRoll.rollDice = function() {
var result = 0;
var results=[];
for (var i = 0; i < newRoll.number; i++) {
var roll = Math.floor(Math.random() * newRoll.sizeOfDice) + 1;
result += roll;
results.push(roll);
}
newRoll.results = results;
newRoll.result = result;
newRoll.Roll = new MakeRoll();
};
self.rolls.push(newRoll);
return self;
};
self.remove = function(index) {
self.rolls.splice(index, 1);
};
self.get = function(index) {
return self.rolls[index];
};
return self;
};
return new MakeRoll();
}
]);
angular service is designed to be singleton to accomplish some business logic, so don't mix up plain model with angular service. if you want to have more objects, just create a constructor and link it in service to be operated on.
function MakeRoll() {
...
}
angular.module('service', []).factory('Roll', function () {
var rolls = [];
return {
add: add,
remove: remove,
get: get
}
function add() {
// var o = new MakrRoll();
// rolls.push(o);
}
function remove(o) {
// remove o from rolls
}
function get(o) {
// get o from rolls
}
});

Node Module Inheritance

I wrote the below listed module for an ExpressJS application. I now need to create a similar module with about 3 changed methods, and a few different instance variables. My plan is to create a superclass that has all the common (call it Common.js) and then require it for the two or more subclasses.
I generalized pointer to a tutorial might help me, but here are my specific questions:
the requires will be common, I suppose I put them in Common.js,
right?
I assume I should promote as many instance variables (the subclasses) into Common as possible?
The following could be a template fro the subclasses, with the Object.create coming at the top of the file
SubClass snippet:
var Common = require("./Common");
SubClass.prototype = Object.create(Common.prototype);
SubClass.prototype.subMethod = function() {....}
and also I assume that any submethod can refer to variables in the superclass, as well as new variables in the subclass, with as this.variableName,
BTW, how would I create new subClass instance variables?
Here is my original Code:
var _ = require('lodash');
var path = require('path');
var fs = require('fs');
var tools = require("../tools/tools");
var Job = require("./falconJob");
var Batch = function (ticket) {
this.counts = [];
this.maxes = [];
this.errors = [];
this.done = [];
this.jobs = 0;
this.started = Date.now();
this.ended = Date.now();
this.jobBatch = {};
this.ticket = ticket;
this.batchRoot = null;
}
Batch.prototype.setup = function (frameList, req, next) {
this.group(frameList);
this.makeRoot(req, next);
}
Batch.prototype.group = function (list) {
_.forEach(list, function (obj) {
if (this.jobBatch[obj.type] == undefined) {
this.jobBatch[obj.type] = [];
}
this.jobBatch[obj.type].push(obj);
}, this);
};
Batch.prototype.makeRoot = function (req, next) {
var config = global.app.settings.config;
this.batchRoot = path.join(config.JobsPath, this.ticket);
var self = this;
fs.mkdir(this.batchRoot, function (err) {
if (err) return next(err);
var mapInfoFile = path.join(self.batchRoot, "MapInfo.json");
var mapInfo = {
Date: (new Date()).toISOString(),
Version: global.manifestVID,
Zoom: req.body.Zoom,
CenterLat: req.body.CenterLat,
CenterLon: req.body.CenterLon
};
fs.writeFile(mapInfoFile, tools.pretty(mapInfo), function (err) {
if (err) return next(err);
return next(null);
});
});
};
Batch.prototype.spawn = function () {
_.forEach(this.jobBatch, function (files, key) {
var job = new Job(key, files, this.batchRoot, this.ticket, this);
this.begin(job);
job.exec();
}, this);
};
Batch.prototype.count = function () {
var sum = 0;
for (var key in this.counts) {
sum += this.counts[key];
}
return sum;
}
Batch.prototype.total = function () {
var sum = 0;
for (var key in this.maxes) {
sum += this.maxes[key];
};
return sum;
}
Batch.prototype.fails = function () {
var sum = 0;
for (var key in this.errors) {
sum += (this.errors[key]) ? 1: 0;
};
return sum;
}
Batch.prototype.finished = function () {
var keylist = Object.keys(this.done);
if (keylist.length == 0) return false;
for (var key in this.done) {
if (this.done[key] == false) return false;
};
if (this.jobs != 0) return false;
return true;
}
Batch.prototype.rate = function () {
var speed = (this.count() * 1000) / (this.ended - this.started); // tiles / second
return speed;
}
Batch.prototype.begin = function (job) {
var type = job.type;
this.jobs++;
this.counts[type] = 0;
this.maxes[type] = 0;
this.errors[type] = false;
this.done[type] = false;
}
Batch.prototype.end = function (job) {
type = job.type;
this.jobs--;
this.errors[type] = job.errors;
this.done[type] = true;
}
Batch.prototype.update = function (status) {
type = status.layer;
this.ended = Date.now();
this.counts[type] = status.tilesCount;
this.maxes[type] = status.tilesMax;
this.done[type] = status.done;
}
module.exports = Batch;
I am surprised, no one answered. Well I have a solution, and a few tips. First, read the Mozilla developer page about an introduction to javascript inheritance: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
Here is how I structured my "sub-module" which I can just require in and it will pull in the super-module, and then subclass it.
var _ = require('lodash'); // require any additional modules that your sub module needs
var BatchRoot = require('./Batch'); // require the super-module with the superclass
var Job = require("./falconJob"); // another module that I need
var Batch = function (ticket) {
BatchRoot.call(this, ticket); // The superclass constructor takes "ticket" as a param
// define new subclass instance variables here, e.g. this.foobar = 33;
}
Batch.prototype = new BatchRoot(); // This does the subclassing
Batch.prototype.constructor = BatchRoot; // MDN says to do this to correct the constructor pointer because it points to Batch
// this is a new subclass function, notice that I use Job which is only defined here
Batch.prototype.spawn = function () {
_.forEach(this.jobBatch, function (files, key) {
var job = new Job(key, files, this.batchRoot, this.ticket, this);
this.begin(job);
job.exec();
}, this);
};
module.exports = Batch;

How to "new" a returned function in Javascript

I am trying to simulate a namespace feature in Javascript.
var com = {};
com.domain = {};
com.domain.system = {};
com.domain.net = {};
com.domain.net.ip = {};
com.domain.net.ip.tcp = {};
com.domain.net.ip.udp = {};
com.domain.net.ip.ssl = {};
com.domain.util = {};
com.domain.util.timer = {};
com.domain.plugins = {};
com.domain.session = {};
com.domain.io = {};
com.domain.algorithm = {};
com.domain.debug = {};
This is the namespaces declaration. Later I will add functions to these namespaces.
This is my selector function:
For a convenient way to use namespaces, I add a function named $. This function will walk all namespaces in com. If the selected name exists, return the object.
function $ (selector) {
function digger (namespace, selector) {
for (var prop in namespace) {
if (typeof namespace[prop] == "array" || typeof namespace[prop] == "object") {
if (prop == selector) {
return namespace[prop];
}
var dig = digger(namespace[prop], selector);
if (dig != null) {
return dig;
}
} else {
if (prop == selector) {
return namespace[prop];
}
}
}
}
return digger (com, selector);
}
After that, I add a timer to namespace com.doamin.util.
com.domain.util.timer = function () {
this._handle = new InnerObj.SystemTimer(io);
return this;
};
com.domain.util.timer.prototype.expiresFromNow = function (seconds, cbHandler) {
this._handle.ExpiresFromNow (seconds, cbHandler);
};
com.domain.util.timer.prototype.wait = function (seconds, cbHandler) {
this._handle.Wait (seconds, cbHandler);
};
com.domain.util.timer.prototype.expiresAt = function (seconds, cbHandler) {
this._handle.Wait (seconds, cbHandler);
};
com.domain.util.timer.prototype.cancel = function () {
this._handle.Cancel ();
};
Usage:
1. var timer = new com.domain.util.timer (); OK
timer.expiresAt (1, {}); OK
2. var func = $("timer"); OK
var timer = new func (); OK
timer.expiresAt (1, {}); OK
But but but but but
var timer = new $("timer") (); NG
Can anyone tell me why the last new function is not working?
Try var timer = new ($("timer"))();.
Your question is not clear but I guess since $("timer") returns a function, you want a new instance of the result of $("timer") and not a new instance of $().

Javascript and module pattern

i think i did not understand javascript module pattern.
I just create this module:
var mycompany = {};
mycompany.mymodule = (function() {
var my = {};
var count = 0;
my.init = function(value) {
_setCount(value);
}
// private functions
var _setCount = function(newValue) {
count = newValue;
}
var _getCount = function() {
return count;
}
my.incrementCount = function() {
_setCount(_getCount() + 1);
}
my.degreeseCount = function() {
_setCount(_getCount() - 1);
}
my.status = function() {
return count;
}
return my;
})();
var a = mycompany.mymodule;
var b = mycompany.mymodule;
console.debug(a, 'A at beginning');
console.debug(a, 'B at beginning');
a.init(5);
b.init(2);
console.log('A: ' + a.status()); // return 2 (wtf!)
console.log('B: ' + b.status()); // return 2`
Where is the mistake?
I thought that my code would have returned to me not 2 value, but 5.
What's the reason?
a and b are the exact same objects.
var a = mycompany.mymodule;
var b = mycompany.mymodule;
What you want to do is create two different objects which have the same prototype. Something similar to this:
mycompany.mymodule = (function () {
var my = function () {};
my.prototype.init = function (value) {
_setCount(value);
};
my.prototype.incrementCount = ...
// ...
return my;
}());
a = new mycompany.mymodule();
b = new mycompany.mymodule();
a.init(5);
b.init(2);
For more info, research "javascript prototypal inheritance"
In JavaScript, objects are passed by reference, not copied.
To explain further, here is a simplified version of your code:
var pkg = (function () {
var x = {};
return x;
}());
var a = pkg;
var b = pkg;
You do not create two separate objects but only reference the object pointed at by pkg from both a and b. a and b are exactly the same.
a === b // true
This means that calling a method on a you are ultimately doing the same to b (it points to the same object—x.)
You don't want to use the module pattern for this. You want the usual constructor+prototype.
function Pkg() {
this.count = 0;
};
Pkg.prototype.init = function (count) { this.count = count; };
var a = new Pkg();
var b = new Pkg();
a === b // false
a.init(2);
a.count === 2 // true
b.count === 2 // false
Here is a good read about module pattern.

Categories

Resources