I am doing slider library and i am confused about fact that i can use my Object ( i used module pattern ) just once. Let me show you:
let PapaSlide = (function(d) {
'use strict';
let _options = {}, _container, _items, _actIndex, _prevIndex;
let _setOptions = function(opt) {
return {
container: opt.container || 'papa-container',
items: opt.items || 'papa-item',
transitionDuration: opt.transitionDuration || '300',
transitionFunction: opt.transitionFunction || 'ease-in',
timeInterval: opt.timeInterval || '3000',
animationType: opt.animationType || 'fade',
type: opt.type || 'auto',
startAt: opt.startAt || 0
}
};
let _setIndexes = function() {
_options.startAt = _options.startAt > _items.length - 1 ? 0 : _options.startAt;
_actIndex = _options.startAt;
_prevIndex = ( _actIndex === 0 ) ? _items.length - 1 : _actIndex - 1;
};
let _addTransitionStyle = function() {
_items.forEach(item => {
item.style.transitionDuration = `${_options.transitionDuration}ms`;
item.style.transitionTimingFunction = _options.transitionFunction;
});
};
let _sliderType = function() {
_setIndexes();
if(_options.animationType === 'fade' && _options.type === 'auto') {
_autoFade();
}
};
let _autoFade = function() {
_items[_actIndex].style.opacity = 1;
setInterval(() => { // is this blocking my other sliders?
_prevIndex = _actIndex;
_actIndex++;
if(_actIndex > _items.length - 1) {
_actIndex = 0;
}
_items[_prevIndex].style.opacity = 0;
_items[_actIndex].style.opacity = 1;
}, parseInt(_options.timeInterval));
};
let setPapaSlider = function(opt) {
_options = _setOptions(opt);
_container = d.getElementsByClassName(_options.container)[0];
if(_container) {
_items = Array.prototype.slice.call(_container.getElementsByClassName(_options.items));
if(_items.length > 0) {
_addTransitionStyle();
_sliderType();
}
else {
console.error('Items have been not found');
}
}
else {
console.error('Container has been not found');
}
};
return {
setPapaSlider: setPapaSlider
}
})(document);
and my main.js
(function(PapaSlide) {
"use strict";
PapaSlide.setPapaSlider({container: 'fade-auto', timeInterval: '1200'});
PapaSlide.setPapaSlider({container: 'fade-self', timeInterval: '2000'});
})(PapaSlide || {});
Actually, just container with 'fade-self' class is sliding, 'fade-auto' is stopped. Is this because javascript has one thread and setInterval is blocking another PapaSlide actions? I have consoled in console options and they have options which i type in arguments, so..? Should i use somewhere clearInterval? But these sliders are infinitive, so i think that i cannot.
EDIT
OK. I did something like this. I have deleted () from IFFE function. A just typed:
let fade1 = new PapaSlide();
fade1.setPapaSlide({container: 'fade-auto'});
let fade2 = new PapaSlide();
fade2.setPapaSlide({container: 'fade-self'});
Is this good solution?
In one line, your second call to PapaSlide.setPapaSlider overrides your first call.
You call setPapaSlider twice, each time with different options. The first line in the function body is:
_options = _setOptions(opt)
so the first time you call it you save the options for 'fade-auto' in the _options variable and the second time you call it, you've overridden it with the options for 'fade-self'. Same goes for the rest of the variable scoped in the PapaSlide function.
If you keep PapaSlide as a simple function like:
let PapaSlide = function(d) {
'use strict';
let _options = {}, _container, _items, _actIndex, _prevIndex;
let _setOptions = function(opt) {
};
let _setIndexes = function() {
};
let _autoFade = function() {
};
let setPapaSlider = function(opt) {
};
return {
setPapaSlider: setPapaSlider
}
};
You can go ahead and do:
let fade1 = PapaSlide(document); //can get rid of document if you are not using it
fade1.setPapaSlide({container: 'fade-auto'});
let fade2 = PapaSlide(document);
fade2.setPapaSlide({container: 'fade-self'});
With this, each call to PapaSlider creates a scope of its own and returns an public interface having setPapaSlider.
Your code as opposed to this creates a public interface {setPapaSlider: Function} and applies new to it which doesn't look good to me
If you are using es6 you could simplify this and make it more readable by using class.
Related
I have created a JavaScript class. I'm getting an error when I try to minify the code using javascript-minifier. Can you help me to fix this issue?
My code:
class Test {
onCompleted = () => {};
onDismissed = () => {};
onError = () => {};
isProgress = false;
popup;
payment;
startPayment(payment) {
this.payment = payment;
this.isProgress = true;
this.popup = window.open('---');
var timer = setInterval(function () {
if (this.Test.popup.closed) {
clearInterval(timer);
if (this.Test.isProgress) {
this.Test.isProgress = false;
this.Test.onDismissed();
}
}
}, 500);
}
}
const Test = new Test();
window.addEventListener('beforeunload', function () {
if (Test.popup != null && !Test.popup.closed) {
Test.popup.close();
}
});
window.Test = Test;
Error message:
// Error : Unexpected token: operator (=)
// Line : 2
// Col : 18
The way you are creating the class seems to be wrong. In classes you can use functions like this: onCompleted() {}; and you can create variables in constructor. I also fixed an issue where you have Test defined twice, one as the class and one as variable. I renamed variable to TestInstance
Here would be a fixed example:
class Test {
constructor() {
this.isProgress = false;
this.popup;
this.payment;
}
onCompleted () {};
onDismissed () {};
onError () {};
startPayment(payment) {
this.payment = payment;
this.isProgress = true;
this.popup = window.open("---");
var timer = setInterval(function () {
if (this.Test.popup.closed) {
clearInterval(timer);
if (this.Test.isProgress) {
this.Test.isProgress = false;
this.Test.onDismissed();
}
}
}, 500);
}
}
const TestInstance = new Test();
window.addEventListener("beforeunload", function () {
if (TestInstance.popup != null && !TestInstance.popup.closed) {
TestInstance.popup.close();
}
});
window.Test = TestInstance;
A minified version:
class Test{constructor(){this.isProgress=!1,this.popup,this.payment}onCompleted(){}onDismissed(){}onError(){}startPayment(s){this.payment=s,this.isProgress=!0,this.popup=window.open("---");var t=setInterval(function(){this.Test.popup.closed&&(clearInterval(t),this.Test.isProgress&&(this.Test.isProgress=!1,this.Test.onDismissed()))},500)}}const TestInstance=new Test;window.addEventListener("beforeunload",function(){null==TestInstance.popup||TestInstance.popup.closed||TestInstance.popup.close()}),window.Test=TestInstance;
I am working the this code and would like to know the difference between
var Point = Geometry.Point and
GelImageLaneViewer.viewers = []
Under what circumstances would I choose to define a var inside a function versus a function.varName?
Code snippet follows from working code :
var GelImageLaneViewer = (function() {
"use strict";
var Point = Geometry.Point,
**Rect = Geometry.Rect**,
harmony = false,
isGel1D = false,
states = {
"identified" : {
"label" : "Identified",
"visible" : true
},
"notAnalyzed" : {
"label" : "Not Analyzed"
}
};
function GelImageLaneViewer(elem) {
var spotToolbar,
svgBox,
spotToolbarBox,
oldViewBox,
newHeight;
ImageViewer.prototype.setViewportPosition('107px', '5px');
ImageViewer.prototype.setRegionsOfInterest($('.gel1d').attr('data-all-regionsofinterest'));
ImageViewer.call(this, elem);
if($('.gel1d').attr('class') === 'hsppImageViewer gel1d') {
isGel1D = true;
}
this.states = {};
svgBox = this.svg.getBoundingClientRect();
this.svg.setAttribute(
"height",
svgBox.height + 'px'
);
**oldViewBox = Rect.fromViewBox(this.svg);**
this.svg.setAttribute(
"viewBox",
[oldViewBox.x, oldViewBox.y, oldViewBox.width, svgBox.height].join(' ')
);
this.image.setAttribute('height', svgBox.height);
}
GelImageLaneViewer.prototype = Object.create(ImageViewer.prototype);
GelImageLaneViewer.prototype.constructor = ImageViewer.constructor;
**GelImageLaneViewer.viewers = [];**
GelImageLaneViewer.noConflict = function () {
harmony = true;
}
window.addEventListener("DOMContentLoaded", function () {
var images = document.querySelectorAll('.hsppImageViewer'),
stop = images.length,
i,
viewer,
src;
if (!harmony) {
for (i = 0; i < stop; i += 1) {
viewer = new GelImageLaneViewer(images[i]);
src = images[i].getAttribute('data-src');
if (!!src) {
viewer.loadURI(src);
}
viewer.initDraw();
**GelImageLaneViewer.viewers.push(viewer);**
}
}
}, false);
return GelImageLaneViewer;
}());
GelImageLaneViewer.viewers will add a property which can be accessed by anything with access to GelImageLaneViewer by asking for GelImageLaneViewer.viewers. Var viewers would create a property which can only be accessed inside the scope of GelImageLaneViewer itself, and wouldn't be visible to anything outside the scope.
So I am using a function to update my values, but I can't then get them back. I see values don't get updated, but is there any way of saving them as a reference to the return of the function.
function Amphibia(wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {
this.speed = 0;
this.mode = mode;
var amphibiaWheel = new PropulsionUnits.Wheel(wheelRadius);
var amphibiaPropeller = new PropulsionUnits.Propeller(finsPerPropeller, propellersSpinDirection);
this.changeMode = function () {
if (mode == "land") {
mode = "water";
}
else if(mode == "water") {
mode = "land";
}
return {
mode: mode
}
}
this.accelerate = function() {
if(this.mode == "water"){
this.speed += amphibiaPropeller.acceleration;
}
else if(this.mode == "land"){
this.speed += 4*amphibiaWheel.acceleration;
}
}
this.changePropellerSpinDirection = function() {
amphibiaPropeller.changeSpinDirection();
}
return {
speed: this.speed,
mode: this.mode,
changeMode: this.changeMode,
accelerate: this.accelerate,
changePropellerSpinDirection: this.changePropellerSpinDirection
}
}
So here I am experiencing problems with changing the mode and the changeMode function expression. Mode in it should refer to this.mode and then I should be able to update the value.
mode and this.mode are not the same. In your functions you are checking/setting values on mode and this.mode, separately.
Either should work fine, as long as you're using one or the other, in the same place, the same way.
Edit
var Amphibia = function (wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {
var amphibia = this,
MODES = { LAND : "land", WATER : "water" };
amphibia.getMode = function () { return mode; };
amphibia.setMode = function (val) { mode = val; };
amphibia.changeMode = function () {
amphibia.setMode((mode === MODES.LAND) ? MODES.WATER : MODES.LAND);
};
};
var amphibia = new Amphibia("", "", "", "land");
amphibia.getMode(); // "land"
amphibia.changeMode();
amphibia.getMode(); // "water"
mode is now 100% private, and unique to that instance.
If you don't need it to be, then you can append it to this, if you'd like.
But here's your problem:
var Amphibia = function () {
var amphibia = this,
amphibiaPropeller = new Propeller( );
// mode, getMode, setMode, etc...
amphibia.accelerate = function () {
if (amphibia.getMode() === "water") {
this.speed += amphibiaPropeller.acceleration;
}
};
};
var amphibia = new Amphibia();
var bob = { speed : 0 };
bob.accelerate = amphibia.accelerate;
bob.accelerate();
// if amphibia.mode === "water", bob.speed += amphibiaPropeller.acceleration
bob.speed; // === amphibiaPropeller.acceleration
setTimeout(amphibia.accelerate, 10); // call amphibia.accelerate in ~10ms
// if amphibia.mode === "water", window.speed += amphibiaPropeller.acceleration
window.speed; // === amphibiaPropeller.acceleration
Be consistent in how you refer to things.
Don't mix self and this, unless you intend to get those side-effects...
And unless you have a very, very good reason to do so (like you're building a framework/engine, not the modules/classes of the game/simulation which use the engine; ie: the difference between building jQuery and building something with jQuery), then you should probably avoid doing it.
If you have closure ("private") state that you want to expose to the outside world, all you need is a function that returns that value, and/or one that sets it.
All of a sudden, the differences between self and this and what is which, when, all go away, as long as you are consistent with how you use them, and you know what the value of this is going to be, every time you call the method.
Notice I'm not returning anything...
When I use new, the value of this (amphibia/self) gets returned by default.
If you want to use private values, and return a "Revealing Module" (which is what I typically prefer), then you can simply do this:
var Amphibia = function (mode) {
var getMode = function () { return mode; },
setMode = function (val) { mode = val; },
changeMode = function () {
setMode( mode === "water" ? "land" : "water" );
};
return {
getMode : getMode,
setMode : setMode,
changeMode : changeMode
};
};
var amphibia = new Amphibia("water");
// `new` won't do any harm, but you can also not use it,
// without it saving everything to `window`
amphibia.getMode(); // "water"
amphibia.changeMode();
amphibia.getMode(); // "land"
Or, maybe if you want that to look a little more like a module/component...
return {
mode : { get : getMode, set : setMode, switch : changeMode }
};
var amphibia = Amphibia("land");
amphibia.mode.get(); // "land"
amphibia.mode.switch();
amphibia.mode.get(); // "water"
var bob = { };
bob.switchAmphibiaMode = amphibia.mode.switch;
bob.switchAmphibiaMode();
amphibia.mode.get(); // "land"
setTimeout(amphibia.mode.switch, 10);
setTimeout(function () { console.log(amphibia.mode.get()); }, 20);
// 10ms amphibia.mode.switch();
// 20ms console.log(amphibia.mode.get());
// > "water"
...or whatever other structure you'd like.
You don't need a this at all.
But this is something to be very, very careful with in JavaScript, because the meaning of this changes every time you call a function, and if half of the code uses this and half uses self, you're bound for some surprises.
I managed to find the answer myself! :) So basicly this in the function constructor refers to Amphibia and this in the this.changeMode function expression refers to object window. Therefore we can define a variable self = this; in the constructor, so we can refer to the same thing in the function expression, as in the function. I explained it a bit awful, but here is my fixed code ;)
function Amphibia(wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {
this.speed = 0;
var self = this;
self.mode = mode;
var amphibiaWheel = new PropulsionUnits.Wheel(wheelRadius);
var amphibiaPropeller = new PropulsionUnits.Propeller(finsPerPropeller, propellersSpinDirection);
this.changeMode = function () {
if (self.mode == "land") {
self.mode = "water";
}
else if(self.mode == "water") {
self.mode = "land";
}
}
this.accelerate = function() {
if(self.mode == "water"){
this.speed += amphibiaPropeller.acceleration;
}
else if(self.mode == "land"){
this.speed += 4*amphibiaWheel.acceleration;
}
}
this.changePropellerSpinDirection = function() {
amphibiaPropeller.changeSpinDirection();
}
return {
speed: this.speed,
mode: this.mode,
changeMode: self.changeMode,
accelerate: this.accelerate,
changePropellerSpinDirection: this.changePropellerSpinDirection
}
}
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
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