Javascript: setInterval isn't removed when nullifying an object - javascript

The setInterval function keeps running even though the object is nullified, should I change the setInterval var to null first or should I do something else? Also, will the GC remove the object even if the setInterval is still running?
Test = function(){
function start(){
// setTimout for controllable FPS
var loop = setInterval(function(){
console.log("TEST");
}, 1000);
}
start();
};
var test = new Test();
setTimeout(function(){
console.log("DIE!!");
test = null;
}, 2000);
JsFiddle

the value returned by setInterval is just a number that used to identify the reference to the interval. you can't just null it - you need to call window.clearInterval on the reference.
there's a few other things that don't make sense in the code you posted. for example, you're declaring a function in a function then just calling it once. i think this is probably closer to what you want:
var Test = function(){
this.start();
}
Test.prototype = {
loop : null,
start : function(){
this.loop = window.setInterval(function(){
console.log('TEST');
}, 1000);
},
stop : function(){
window.clearInterval(this.loop);
}
}
var test = new Test();
window.setTimeout(function(){
test.stop();
}, 5000);
That'll run the interval 5 times.
FWIW, the GC isn't really involved here. As long as there's a reference to any variable, it won't be collected.
HTH

Related

Array.pop() Isn't killing my setInterval

I've written some code that when you click a button it adds an instance of a function to an array,
var objects = [];
$(document).on("click", ".addButton", function(){
objects.push(new newObject(1));
});
function newObject(amount){
setInterval(function(){
addValue(amount);
}, 1000);
}
So then every second each new object created keeps running the addValue function every second adding the amount.
The problem is when I try and destroy that function with objects.pop() it deletes the object but the setInterval doesn't stop running.
How do I make it destroy everything in that function and stop it from running?
There is nothing quite like that in JS for setInterval. I would suggesting declaring a method to handle clean up.
// "Class" declaration
function newObject(amount) {
var id = setInterval(function() {
addValue(amount);
}, 1000);
this.kill = function() {
clearInterval(id);
}
}
// "Public" api for the data structure
var objects = [];
function addNewObject() {
objects.push(new newObject(1));
}
function destroyLastObject() {
objects.pop().kill();
}
// Event bindings
$(document).on("click", ".addButton", addNewObject);
$(document).on("click", ".removeButton", destroyLastObject);
Completely untested, but along these lines should work.
EDIT
This, imo, is a great resource for learning about different patterns within javascript - long but well well worth the read: https://addyosmani.com/resources/essentialjsdesignpatterns/book/
You got to find something to check against to clear the interval. I am clearing based on array length. It only executes once.
// you got to find something to check against to clear the interval
var objects = [];
document.addEventListener("click", function(){
console.log('click');
objects.push(new newObject(1));
});
function newObject(amount){
var interval= setInterval(function(){
if(objects.length !==0){
clearInterval(interval);
}
}, 1000);
}

call clear interval function from another function without pass the interval variable

I need to clear an interval from another function
window.onload = function(){
var interval = null;
interval = setInterval(function(){
myFunction();
}, 1000);
function stop(){
clearInterval(interval);
}
}
without pass the interval variable
stop();
But I cannot make it working: when I call stop(); the interval continues...
How can I do?
There is an unexpected window.stop function which preexists yours.
That's another proof that global variables/functions are evil.
It might be this function which gets invoked instead of yours, depending on when the script is loaded.
Try to put your function in an object to protect namespaces:
It works in the StackOverflow fiddle:
var i = 0;
function myFunction() {
i++;
console.log(i);
}
var interval = null;
interval = setInterval(function() {
myFunction();
}, 1000);
var myObject = {
stop: function() {
console.log("stopping");
clearInterval(interval);
}
};
<button onclick="myObject.stop();">stop</button>
In the faulty jsFiddle, you get things in iframes, meaning window element is not the same. That's why your function is not invoked. That gives you that kind of errors:
You can put your script in the html to get it working:
jsfiddle
You could simply put something like var interval = null; at the beginning of the JavaScript outside of a function.
It's all about variable scope. A variable defined inside of a function is only available within that function. A variable defined outside of a function or object will be available globally to all functions.
What is the scope of variables in JavaScript?
I found also this solution working:
stop = function(){
clearInterval(interval);
}
The presumption on the answer you've checked as solution is wrong.
Your stop function wouldn't be working regardless of the fact that there are browsers supporting load stop command programmatically.
This [stop] command is a window property and can be deleted and\or be overwritten by a simple variable declaration or by a function with the same name anywhere on the script.
The reason you are not being able to call the stop function ( from the outside ), is because it's a closure.
Regards.
p.s.:
throwing it up on global scope will make it work, visit you fiddle
var i=0;
function myFunction(){
i++;
$('i').html(i);
}
interval = null;
interval = setInterval(function(){
myFunction();
}, 100);
stop = function(){
clearInterval(interval);
}

Why does setInterval initiate when I'm only assigning it?

I'm assigning to a variable, a function that uses setInterval, but I don't want the function to run until I call it. However, the function is running from just the assignment statement.
sessionClock = setInterval(function() {
console.log("Hi")
}, 1000)
I have also tried like this:
sayHi = function() {
console.log("Hi");
}
var sayHiStarter = setInterval(sayHi, 1000);
Both of these initiate the function and will log "Hi" to the console.
Why is it running on assignment? And what can do I do fix this?
If you only want to bind a function to setInterval, but call it later, you can use bind:
var sessionClock = setInterval.bind(null, function() {
console.log("Hi")
}, 1000);
//... later
var myInterval = sessionClock(); // start the timer
// ... later if you need to clear it
clearInterval(myInterval);
In principle, bind returns a new function that calls your original function (in this case, setInterval) with predefined arguments. So when you call sessionClock, that returned function is called. There a other aspects to bind, but they don't seem to apply in this context.
The call to setInterval does not return a function, but an identification for the created interval. This id is used to remove the interval when you don't want it to execute anymore:
sessionClock = setInterval(function() {
console.log("Hi")
}, 1000)
...
clearInterval(sessionclock);
What you want is something like this:
sessionClock = function () {
return setInterval(function() {
console.log("Hi")
},
1000);
}
//When needed
var intervalId=sessionClock();

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

Javascript setInterval function to clear itself?

myInterval = setInterval(function(){
MyFunction();
},50);
function MyFunction()
{
//Can I call clearInterval(myInterval); in here?
}
The interval's not stopping (not being cleared), if what I've coded above is fine then it'll help me look elsewhere for what's causing the problem. Thanks.
EDIT: Let's assume it completes a few intervals before clearInterval is called which removes the need for setTimeout.
As long as you have scope to the saved interval variable, you can cancel it from anywhere.
In an "child" scope:
var myInterval = setInterval(function(){
clearInterval(myInterval);
},50);
In a "sibling" scope:
var myInterval = setInterval(function(){
foo();
},50);
var foo = function () {
clearInterval(myInterval);
};
You could even pass the interval if it would go out of scope:
var someScope = function () {
var myInterval = setInterval(function(){
foo(myInterval);
},50);
};
var foo = function (myInterval) {
clearInterval(myInterval);
};
clearInterval(myInterval);
will do the trick to cancel the Interval whenever you need it.
If you want to immediately cancel after the first call, you should take setTimeout instead. And sure you can call it in the Interval function itself.
var myInterval = setInterval(function() {
if (/* condition here */){
clearInterval(myInterval);
}
}, 50);
see an EXAMPLE here.
var interval = setInterval(function() {
if (condition) clearInterval(interval); // here interval is undefined, but when we call this function it will be defined in this context
}, 50);
Or
var callback = function() { if (condition) clearInterval(interval); }; // here interval is undefined, but when we call this function it will be defined in this context
var interval = setInterval(callback, 50);
From your code what seems you want to do is to run a function and run it again and again until some job is done...
That is actually a task for the setTimeout(), the approach is similar:
var myFunction = function(){
if( stopCondition ) doSomeStuff(); //(do some stuff and don't run it again)
else setTimeout( myFunction, 50 );
}
myFunction(); //immediate first run
Simple as that :)
Of course if you REALLY want to use setInterval for some reason, #jbabey's answer seems to be the best one :)
You can do it by using a trick with window.setTimeout
var Interval = function () {
if (condition) {
//do Stuff
}
else {
window.setTimeout(Interval, 20);
};
};
window.setTimeout(Interval, 20);

Categories