Safely clear JavaScript timeout - javascript

I have created a JavaScript function that does the following:
function myFunction() {
DoStuff;
watch = setTimeout(myFunction, 1000);
}
where
watch
is a global variable initially set to null.
Then, I have a second function, that can be called at any moment, of the form:
function mySecond() {
DoStuff;
clearTimeout(watch);
}
Now, it happens sometimes that, although the second function is called and the timeout is somehow cleared, the first function is called another time. I guess this is happening because when the second function is called, a request for the first function has already been sent, and thus the timer works another time, and keeps calling itself over and over... I would like to point out that this does not happen always, I guess it depends on a specific timing condition you can encounter.
How to safely remove ALL the possibilities that the first function is called again?

Problem with this code is watch holds the last timeout only. This should fix it
function myFunction() {
DoStuff;
if (watch) { clearTimeout(watch); }
watch = setTimeout(myFunction, 1000);
}

Related

Javascript check if a function has been created on other file

Hey i am creating a DOM javascript library and i found myself having the following problem:
For example, if i take a function lets say function update() how can i check if this function has been created on another file; If it has been created on another file how can I make it run once or every couple of seconds without the user need to do this?
For example in the library p5.js :
//If this function has created on this file it will run every one second
function update(){
}
&&
//if this function has created on this file it will call itself once the page is loaded
function start(){
}
*Edit: tried to be more clear on my question thank you for your answers!
Instead of the user needing to call setInterval() to repeat update(), it can call it itself.
function update() {
setInterval(function() {
// do something
}, 1000);
}
All the actual work that needs to be done goes where // do something is.
setTimeout(func, 1000) will call func 1000 milliseconds later.
If you wanted your function to call immediately, you could do a recursion (bad way, better use a loop, but it's useful to illustrate the next example):
// calls itself infinitely, without any delay
function update(){
update(); // Will cause a stack overflow, infinitely deep recursion
}
Now you can make use of setTimeout and tell update to run a second later.
// calls itself infinitely, 1 second delay between calls
function update(){
setTimeout(update, 1000);
}
There is no recursion here. Instead, you defer the call to update() for one second. The second time update() is called, another setTimeout will be called, and so on infinitely.
The second part of your question:
//call itself once the page is loaded
function start(){
}
You can set an event listener to when the page is loaded, and call that function:
window.addEventListener('load', start);
Do this right after defining start().
To reflect your comment:
If you want to detect if the global function update has been defined (by the user, probably) and want to start calling it automatically on equal intervals of 1 second, you'll need to check its existance with typeof and then apply setInterval on it:
if(typeof update === "function") {
setInterval(update, 1000);
}
To make it explicit that you're refering to a global update and not a local variable, you can use window.update instead. In that case, you could also check if it exists this way:
if(update in window)

Calling JavaScript Function that has SetTimeout Assigned to It

I'm not 100% sure how setTimeout works in JavaScript. Say I have something like this:
$(document).ready(function() {
testTimeout();
});
function testTimeout() {
alert("testing timeout");
setTimeout(testTimeout, 5000);
}
This would display a popup window every 5 after the page is ready. What would happen if then I called testTimeout from a button click?
$("#button").click(function() {
testTimeout();
});
Would the button click call testTimeout and add another timeout every 5 seconds? Or, would the button click reset the timeout from when the button was pressed? The reason I am asking is because I would like to design something like this where I can pass a parameter to my timeout function. When the web page starts up, I have a default parameter. However, if I press a button, I would like my timeout function to be called right away and every 5 seconds after with my new parameter. But, I don't want the timeout function with the old parameter to continue repeating. How can I achieve this? Any help and understanding would be greatly appreciated.
This would display a popup window every 5 after the page is ready.
No it wouldn't, it would show an alert repeatedly with no delay and/or cause a "too much recursion" error, because setTimeout(testTimeout(), 5000) calls testTimeout and passes its return value into setTimeout, just like foo(bar()) calls bar and passes its return value into foo.
If you remove the ():
function testTimeout() {
alert("testing timeout");
setTimeout(testTimeout, 5000);
// here --------------^
}
Then it would do that.
What would happen if then I called testTimeout from a button click?
You'd end up with the function being called twice as often (more than once every 5 seconds), because every time you call it, it reschedules itself. A third time would make it more frequently still (three times/second), and so on.
If you want to avoid that, one option is to remember the timer handle and cancel any outstanding timed callback if you call the function before then:
var handle = 0;
function testTimeout() {
clearTimeout(handle); // Clears the timed call if we're being called beforehand
alert("testing timeout");
handle = setTimeout(testTimeout, 5000);
}
(I initialized handle with 0 because calling clearTimeout with a 0 is a no-op.)
Have you tried to asign variable to your setinterval;
var foo = setTimeout(testTimeout(), 5000);
and then when right event comes just destroy that variable.
clearInterval(foo);
And now you can asign it again...
In your case it would simply repeat endlessly, because you're executing the function instead of passing the reference. You should do it like this:
function testTimeout() {
alert("testing timeout)";
setTimeout(testTimeout, 5000);
}
Note the missing braces after testTimeout. This tells setTimeout to execute that function, instead of the result of that function, which is how your original code behaved.
" I would like my timeout function to be called right away and every 5 seconds after with my new parameter. But, I don't want the timeout function with the old parameter to continue repeating "
In order to achieve what you're trying to do you should remove the timeout:
var timeoutId;
function testTimeout() {
alert("testing timeout)";
clearTimeout(timeoutId );
timeoutId = setTimeout(testTimeout, 5000);
}
Notes:
You can stop the previous timeoutI from firing by catching the id returned from the setTimeout method and passing that to the clearTimeout method

setinterval causing my app to crash

Can anyone explain why this is causing my app to crash? It always crashes on the second iteration of the loop.
function FetchMetaData () {
alert("Am I being fired");
}
var timer= setInterval(FetchMetaData(),10000);
It's not "crashing"; you're just calling the function once. You should pass the function itself to setInterval(), not the result of calling the function:
var timer = setInterval(FetchMetaData, 10000);
When you write it as FetchMeData(), that means that the function should be called right then and there, and that whatever value it returns should be what's passed to setInterval(). Sometimes that makes sense, but in this case you need to pass a reference to your function. You do that in JavaScript by simply using the name of the function without calling it.

Check when the last function

If i'm calling 2 or 3 times a function, like this:
somefunction();
somefunction();
How could i know when is the last time the function has been called?
i'm asking that because i want the last function to do one more thing.
Pass a parameter that determines whether the function should do "one more thing"
somefunction(false);
somefunction(true);
You could set a timeout when the function is called, then the code will be called as soon as you exit from your first function returning control to the browser:
var timer = null;
function somefunction() {
// do something
if (timer == null) {
timer = window.setTimeout(function(){
// do one last thing
}, 0);
}
}
Demo: http://jsfiddle.net/Guffa/Fa5j3/
You can't know this.
If you know how often it is called, you can count down a variable.
If you don't know how often it is called you can start a timeout and call the special function. If you call someFunction again you cancel the old timeout and start a new timeout.

stop settimeout in recursive function

my problem is that I can not stop a timer.
I had this method to set a timeout from this forum.
It supposed to store the identifyer in the global variable.
By accident, I found out that it is still running after I hide "mydiv".
I also need to know now, if the recursive function creates multiple instances or just one for the timeouts. Because first I thought that it overwrites "var mytimer" everytime.
Now I am not so sure.
What would be a solid way to stop the timer??
var updatetimer= function () {
//do stuff
setTimeout(function (){updatetimer();}, 10000);
}//end function
//this should start and stop the timer
$("#mybutton").click(function(e) {
e.preventDefault();
if($('#mydiv').is(':visible')){
$('#mydiv').fadeOut('normal');
clearTimeout(updatetimer);
}else{
$('#mydiv').fadeIn('normal');
updatetimer();
}
});
thanks, Richard
I think that most people are getting at the reason why this isn't working, but I thought I would provide you with updated code. It is pretty much the same as yours, except that it assigns the timeout to a variable so that it can be cleared.
Also, the anonymous function in a setTimeout is great, if you want to run logic inline, change the value of 'this' inside the function, or pass parameters into a function. If you just want to call a function, it is sufficient to pass the name of the function as the first parameter.
var timer = null;
var updatetimer = function () {
//do stuff
// By the way, can just pass in the function name instead of an anonymous
// function unless if you want to pass parameters or change the value of 'this'
timer = setTimeout(updatetimer, 10000);
};
//this should start and stop the timer
$("#mybutton").click(function(e) {
e.preventDefault();
if($('#mydiv').is(':visible')){
$('#mydiv').fadeOut('normal');
clearTimeout(timer); // Since the timeout is assigned to a variable, we can successfully clear it now
} else{
$('#mydiv').fadeIn('normal');
updatetimer();
}
});
I think you misunderstand 'setTimeout' and 'clearTimeout'.
If you want to set a timer that you want to cancel later, do something like:
foo = setTimeout(function, time);
then call
clearTimeout(foo);
if you want to cancel that timer.
Hope this helps!
As written mytimer is a function which never has the value of a timeout identifier, therefore your clearTimeout statement will achieve nothing.
I don't see any recursion here at all, but you need to store the value setTimeout returns you, and if you need to pair this with multiple potential events you need to store it against a key value you can lookup - something like an element id perhaps?
This is a simple pseudocode for controlling and conditioning recursive setTimeout functions.
const myVar = setTimeout(function myIdentifier() {
// some code
if (condition) {
clearTimeout(myIdentifier)
} else {
setTimeout(myIdentifier, delay); //delay is a value in ms.
}
}, delay);
You can not stop all the functions that are created, intead of that convert the function to setInterval (represent the same logic that your recursive function) and stop it:
// recursive
var timer= function () {
// do stuff
setTimeout(function (){timer();}, 10000);
}
The same logic using setInterval:
// same logic executing stuff in 10 seconds loop
var timer = setInterval(function(){// do stuff}, 10000)
Stop it:
clearInterval(timer);
As noted above, the main reason why this code isn't working is that you're passingt he wrong thing into the clearTimeout call - you need to store the return value of the setTimeout call you make in updateFunction and pass this into clearTimeout, instead of the function reference itself.
As a second suggestion for improvement - whenever you have what you call a recursive timeout function, you would be better off using the setInterval method, which runs a function at regular intervals until cancelled. This will achieve the same thing you're trying to do with your updateFunction method, but it's cleaner as you only need to include the "do stuff" logic in the deferred function, and it's probably more performant as you won't be creating nested closures. Plus it's The Right way to do it which has got to count for something, right? :-)
(function(){
$('#my_div').css('background-color', 'red');
$('#my_div').hover(function(){
var id=setTimeout(function() {
$('#my_div').css('background-color', 'green');
}, 2000);
var id=setTimeout(function() {
$('#my_div').css('background-color', 'blue');
}, 4000);
var id=setTimeout(function() {
$('#my_div').css('background-color', 'pink');
}, 6000);
})
$("#my_div").click(function(){
clearTimeout(id);
})
})();

Categories

Resources