Interval still firing but inaccessible - javascript

I have a variable created with setInterval called cycle1. It is created with setInterval inside of a prototyped function to an object called eGi, which is the same as $_. After creating it, it still fires, but is inaccessible to the rest of the script and the console. When I try to clear this interval from another prototyped function, nothing happens.
eGi.prototype.startGame = function() {
//other code...
if (somethingOrOther) {
var somethingElse = confirm("start interval?");
if (somethingElse) {
this.cycle1 = setInterval($_.cycle,toMS(INTERVAL_SECONDS));
}
} else {
this.cycle1 = setInterval($_.cycle,toMS(INTERVAL_SECONDS));
}
};
then when i try and stop it in another function
eGi.prototype.gameOver = function() {
clearInterval(this.cycle1);
//other code...
if (restart) {
$_.startGame();
} else {
$_.mainMenu();
}
};
It never gets cleared, and seems to be created again in the calling of $_.startGame. I can't even access it from the Chrome console using $_.cycle1 or the eGi instance variable, egi.cycle1. The strange thing is, this works for accessing any other variable that belongs to my eGi object:
var eGi = function(console,cDom,ctxt,game,devMode) {
$_ = this;
this.game = game;
this.cDom = cDom; //specifically, these objects control the canvas' DOM
this.ctxt = ctxt; //and the CanvasRenderingContext2D
}
eGi.prototype.mainMenu = function() {
this.ctxt.fillText("Hello",250,250); //this works just fine
//etc
};
Why isn't it being cleared?
Full code/game here.

It's a nice game...
The problem is you are referring to "this" inside gameover which doesn't contain reference to cycle1 (undefined).
Instead you have to store "cycle1" as part of an object which can be referenced from your other function (in this case gameover)
Making variables as global is not a good thing. Instead you can store the "cycle1" as part of eGi or any such namespace or object.
Refer here (working code): JSFiddle implementation
Javascript code (start and stop are input buttons)
var eGi = {};
$('#start').click(function start() {
var somethingElse = confirm("start interval?");
if (somethingElse) {
eGi.cycle1 = setInterval(function(){
console.log('Running...');
},1000);
}
});
$('#stop').click(function stop(){
clearInterval(eGi.cycle1);
});
​

Related

How can I end a requestanimationFrame with a function? [duplicate]

I'm trying to cancel a requestAnimationFrame loop, but I can't do it because each time requestAnimationFrame is called, a new timer ID is returned, but I only have access to the return value of the first call to requestAnimationFrame.
Specifically, my code is like this, which I don't think is entirely uncommon:
function animate(elem) {
var step = function (timestamp) {
//Do some stuff here.
if (progressedTime < totalTime) {
return requestAnimationFrame(step); //This return value seems useless.
}
};
return requestAnimationFrame(step);
}
//Elsewhere in the code, not in the global namespace.
var timerId = animate(elem);
//A second or two later, before the animation is over.
cancelAnimationFrame(timerId); //Doesn't work!
Because all subsequent calls to requestAnimationFrame are within the step function, I don't have access to the returned timer ID in the event that I want to call cancelAnimationFrame.
Looking at the way Mozilla (and apparently others do it), it looks like they declare a global variable in their code (myReq in the Mozilla code), and then assign the return value of each call to requestAnimationFrame to that variable so that it can be used any time for cancelAnimationFrame.
Is there any way to do this without declaring a global variable?
Thank you.
It doesn't need to be a global variable; it just needs to have scope such that both animate and cancel can access it. I.e. you can encapsulate it. For example, something like this:
var Animation = function(elem) {
var timerID;
var step = function() {
// ...
timerID = requestAnimationFrame(step);
};
return {
start: function() {
timerID = requestAnimationFrame(step);
}
cancel: function() {
cancelAnimationFrame(timerID);
}
};
})();
var animation = new Animation(elem);
animation.start();
animation.cancel();
timerID; // error, not global.
EDIT: You don't need to code it every time - that's why we are doing programming, after all, to abstract stuff that repeats so we don't need to do it ourselves. :)
var Animation = function(step) {
var timerID;
var innerStep = function(timestamp) {
step(timestamp);
timerID = requestAnimationFrame(innerStep);
};
return {
start: function() {
timerID = requestAnimationFrame(innerStep);
}
cancel: function() {
cancelAnimationFrame(timerID);
}
};
})();
var animation1 = new Animation(function(timestamp) {
// do something with elem1
});
var animation2 = new Animation(function(timestamp) {
// do something with elem2
});

Javascript clearInterval of interval set in another scope

Still getting the hang of javascript and am not sure how I do this..
I am using intervals to send error and success messages on a page and have run into some issues.
Let's say I have a the following:
function setMyInterval(element) {
var timer = setInterval(function() {
// add some child nodes to element
// play with the css
}, 20);
return timer;
}
function callMyInterval() {
var parent = document.getElementById("element");
var myIntervalRef;
if(!parent.firstChild) {
myIntervalRef = setMyInterval(parent);
} else {
clearInterval(myIntervalRef);
while(parent.firstChild) {
parent.removeChild(parent.firstChild);
}
myIntervalRef = setMyInterval(parent);
}
}
<button onclick="callMyInterval();" >Reset</button>
How would I clear the interval in this case? I have tried a few variations of above, but not successful. I think the problem is due to myIntervalRef not having a reference to the previous call of the function, but not sure how to correct this.
Thanks to all in advanced!!!
You need to define the interval variable outside of the function scope so that subsequent calls to the callMyInterval will refer to the same instance.
You have defined it in the local scope of the function so every call to callMyInterval will refer to a new variable instance so you will not get reference to the previous timer.
var myIntervalRef;
function callMyInterval() {
var parent = document.getElementById("element");
if (parent.firstChild) {
clearInterval(myIntervalRef);
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
}
myIntervalRef = setMyInterval(parent);
}
Simple, move your myIntervalRef outside as a globally accessible function will do. Doing so will allow other functions to access it and make changes to it.
// Moving the function reference outside of the method, so other function can access it.
var myIntervalRef;
function setMyInterval(element) {
var timer = setInterval(function() {
// add some child nodes to element
// play with the css
}, 20);
return timer;
}
function callMyInterval() {
var parent = document.getElementById("element");
if(!parent.firstChild) {
myIntervalRef = setMyInterval(parent);
} else {
clearInterval(myIntervalRef);
while(parent.firstChild) {
parent.removeChild(parent.firstChild);
}
myIntervalRef = setMyInterval(parent);
}
}
<button onclick="callMyInterval();" >Reset</button>
Hope this helps.
In your code:
var myIntervalRef;
Is local variable of your function, make it global is fastest way to fix

Is there a way to cancel requestAnimationFrame without a global variable?

I'm trying to cancel a requestAnimationFrame loop, but I can't do it because each time requestAnimationFrame is called, a new timer ID is returned, but I only have access to the return value of the first call to requestAnimationFrame.
Specifically, my code is like this, which I don't think is entirely uncommon:
function animate(elem) {
var step = function (timestamp) {
//Do some stuff here.
if (progressedTime < totalTime) {
return requestAnimationFrame(step); //This return value seems useless.
}
};
return requestAnimationFrame(step);
}
//Elsewhere in the code, not in the global namespace.
var timerId = animate(elem);
//A second or two later, before the animation is over.
cancelAnimationFrame(timerId); //Doesn't work!
Because all subsequent calls to requestAnimationFrame are within the step function, I don't have access to the returned timer ID in the event that I want to call cancelAnimationFrame.
Looking at the way Mozilla (and apparently others do it), it looks like they declare a global variable in their code (myReq in the Mozilla code), and then assign the return value of each call to requestAnimationFrame to that variable so that it can be used any time for cancelAnimationFrame.
Is there any way to do this without declaring a global variable?
Thank you.
It doesn't need to be a global variable; it just needs to have scope such that both animate and cancel can access it. I.e. you can encapsulate it. For example, something like this:
var Animation = function(elem) {
var timerID;
var step = function() {
// ...
timerID = requestAnimationFrame(step);
};
return {
start: function() {
timerID = requestAnimationFrame(step);
}
cancel: function() {
cancelAnimationFrame(timerID);
}
};
})();
var animation = new Animation(elem);
animation.start();
animation.cancel();
timerID; // error, not global.
EDIT: You don't need to code it every time - that's why we are doing programming, after all, to abstract stuff that repeats so we don't need to do it ourselves. :)
var Animation = function(step) {
var timerID;
var innerStep = function(timestamp) {
step(timestamp);
timerID = requestAnimationFrame(innerStep);
};
return {
start: function() {
timerID = requestAnimationFrame(innerStep);
}
cancel: function() {
cancelAnimationFrame(timerID);
}
};
})();
var animation1 = new Animation(function(timestamp) {
// do something with elem1
});
var animation2 = new Animation(function(timestamp) {
// do something with elem2
});

Calling nested function from nested setInterval in an Object Namespace environment

I have this following piece of code:
var stats = {
....,
checkExistance :
function(url){
var newUrl = url.substring(0, url.lastIndexOf("/")) + "/asyncCheckChartExistance";
var xhrObj = stats.getXhr();
var poolInterval = setInterval("poll()", 100);
function poll(){
xhrObj.open("GET", newUrl, true);
xhrObj.send(null);
xhrObj.onreadystatechange = function(){
if(xhrObj.readyState === 4 && xhrObj.status === 200){
if (xhrObj.responseText.length === true){
console.log("Exists!");
clearInterval(poolInterval);
} else {
console.log("Not Yet!");
}
}
}
}
},
}
I created the stats namespace. In this namespace I'm trying to create a function which polls the server every second. I should access this function this way: stats.checkExistance(myUrl).
However it seems that the setInterval function is not able to see the poll() function. I know that this is normal behavior taking in consideration that these are nested inside another function.
If I were to write this in the Global namespace there would be no problem but I'm interested to make this work in this kind of namespace. Any ideas? Thanks!
when you pass a string to setInterval, it runs in the global scope, by default, where poll would not be defined since it only exists in the scope of the checkExistance function.
To fix the issue, pass an anonymous function to setInterval instead:
var poolInterval = setInterval(function () {
poll();
}, 100);
Passing an anonymous function is usually the best idea as it allows you to write any javascript expressions/statements for the interval instead of just calling one function.
When you pass a string to setInterval, that string is interpreted as global code, and since poll is not a global function, a reference error is thrown.
However, you can pass a function reference instead of a string, and since the poll function is available in the scope in which the setInterval invocation is made, you can just write this:
var poolInterval = setInterval( poll, 100 );
var stat = {
say: function(name){
function doit(){
console.log(name);
}
setInterval(doit, 1000);
}
};
stat.say("hi");​​​​​​​​​​​
A simple demo to show how. You will see "hi" every second.

How to pass timeout by reference? Or a better way to implement?

I had this code working previously, but I am not so sure now that I have separated my HTML controls from my jQueryUI Widget.
Currently, the timer starts correctly, but I lose my reference to _refreshTimeout after one tick. That is, after the first tick, unchecking my PlanViewRefreshCheckbox does not stop my timer from running.
I have two JavaScript files, PlanView.js and PlanViewCanvas.js.
PlanView.js looks something like this:
(function ($) {
var _minZoom = -2.0;
var _maxZoom = 2.0;
var _stepZoom = (_maxZoom - _minZoom) / 100;
var _refreshTimeout = null;
var _refreshInterval = 60000; //One minute
$(document).ready(function () {
//Initialize Refresh combo box.
$('#PlanViewRefreshCheckbox').click(function () {
if ($(this).is(':checked')) {
var planViewCanvas = $('#PlanViewCanvas');
//Binding forces the scope to stay as 'this' instead of the domWindow (which calls setTimeout).
_refreshTimeout = setTimeout(function(){planViewCanvas.PlanViewCanvas('refresh', _refreshInterval, _refreshTimeout)}.bind(planViewCanvas), _refreshInterval)
}
else {
clearTimeout(_refreshTimeout);
}
});
}
})(jQuery);
and PlanViewCanvas.js houses a jQueryUI Widget:
(function ($) {
$.widget("ui.PlanViewCanvas", {
//other properties and methods not-relevant to problem declared here.
refresh: function (refreshInterval, refreshTimeout) {
var self = this;
_stage.removeChildren();
self.initialize();
//Binding forces the scope to stay as 'this' instead of the domWindow (which calls setTimeout).
refreshTimeout = setTimeout(function () { self.refresh(refreshInterval, refreshTimeout) }.bind(self), refreshInterval);
},
}
})(jQuery);
Does it seem like I am going about things incorrectly?
EDIT: I think the answer is probably to use setInterval and not setTimeout.
The first problem is that you forgot the underscore
refreshTimeout should be _refreshTimeout
second, your variable needs to be global to be accessible in both files, so declare it outside of the function:
var _minZoom = -2.0;
var _maxZoom = 2.0;
var _stepZoom = (_maxZoom - _minZoom) / 100;
var _refreshTimeout = null;
var _refreshInterval = 60000; //One minute
(function ($) {
....
})(jQuery)
You can't pass values by reference. I see two options:
pass an Object. If you have it referenced from two variables, you can access its properties in both scopes.
split up you functionality in two functions, where it belongs: One masters the interval loop and triggers the refresh function, and the other does things to refresh. The refreshTimeout variable only belongs to the scope of the first one. point. You may add the interval function to you widget if it is often needed.
The answer was very 'oh derp.'
//Initialize Refresh combo box.
$('#PlanViewRefreshCheckbox').click(function () {
if (this.checked) {
_refreshTimeout = setInterval(function(){$('#PlanViewCanvas').PlanViewCanvas('refresh')}, _refreshInterval)
}
else {
clearTimeout(_refreshTimeout);
}
});

Categories