I have a function that sets a timer, and calls itself back upon expiration of the timer.
What I'd like to know is if it is bad practice to clear the timer at the top of the function.
The reason for this is because I will be calling that function asynchronously from time to time, and if I don't clear the timer first, I'll have two running simultaneously.
I realize that I can clear the timer right before I make the other call to the function, but I'm wondering if it will cause problems in any browser if I just keep the cleartimeout call inside the function which contains the timer.
One other thought - Can I test the timer variable before making the cleartimeout call, to see if it is a timer?
Here is some example code:
function onAir(){
// reset timer
clearTimeout(timer);
$.getJSON("http://mywebsite.com?format=json&callback=?",function(data){
if(data.result == '1'){
do stuff here
}
else{
do other stuff here
}
});
// start timer
timer = setTimeout("onAir()",60000);
}
Thanks for sharing your brain with me!
Kenny
Yes, that's fine. Also, you should call "setTimeout()" like this:
timer = setTimeout(onAir, 60000);
Yes you can call clearTimeout on a nullvariable.
Also i would suggest you change your setTimeout so it won't use eval:
timer = setTimeout(onAir,60000);
Yes, you can call a clearTimeout on a null variable and the world won't implode.
Yes you can call clearTimeout(timer), but there are some edge cases where it may cause issues.
If timer had been previously set with some other integer value, you might be killing off a completely unrelated timer.
setTimeout just returns an integer index for the timer. If you're not sure if a timer has been previously set, you could add a check before calling clearTimeout:
if (window.timer)
{
clearTimeout(timer);
}
...
timer = setTimeout(onAir, duration);
A solution to the possible pollution of the timer variable is to use a closure:
(function(){
var timer,
duration;
duration = 60000;
window.onAir = function onAir(){
...code...
if (timer){
clearTimeout(timer);
}
timer = setTimeout(onAir,duration);
};
});
Clearing a Timeout raises not problem to me (but i am not a javascript guru).
Btw, you can find intersting things (checking an existing Timeout) on this thread: Check if a timeout has been cleared?
Related
I have a quick question about using recursive setTimeOut recursively and a clearTimeOut that get called somewhere else.
On rare cases, will there ever gonna be a bug where clearTimeOut doesn't actually stop the loop? Is it possible that the timeOutID get changes into a new value and clearTimeout is called on the old value?
Here is the code:
timeOutID = 0;
function timeOutRecusive() {
timeOutID = setTimeout('timeOutRecusive();', 1000);
}
function killTimeOutRecusive() {
clearTimeout(timeOutID);
}
//when page started.
start() {
timeOutRecusive();
}
//When a button is press, calls killTimeOutRecursive();
EDIT: I have some typo in my code. It should be 'timeOutID' instead of clockID. clearTimeOut should be 'clearTimeout' (using its built-in)
This approach is pretty bullet-proof, and a standard practice.
Is it possible that the timeoutId get changes into a new value and clearTimeout is called on the old value?
No, this is not possible. JS code doesn't run in parallel, there are no data races from multithreading.
The only edge case where killTimeoutRecursive does not work as expected is when it is called from within timeoutRecursive, after the old timeout occurred and before the new one was created:
var timeoutId = 0;
function timeoutRecusive() {
callback();
timeoutId = setTimeout(timeOutRecusive, 1000);
}
function killTimeoutRecusive() {
clearTimeout(timeoutId);
}
function callback() { // this might be user-provided
killTimeoutRecursive();
}
Your thought is legit. If the callback method of the specified timeout would be called in a parallel execution, it could just create a new timeout (not yet updated the variable) while you try to clear the current timeout.
However, the timeout handling is executed sequential. (thats why it some times can take way longer than 1000ms for the callback to be fired)
Meaning:
-If your code is just about to create a new timeout, your clear call "waits" and then clears the 3ms old timer.
-If you are just about to clear the timeout, when 1000 ms have elapsed, the callback will not be fired, as long as your code is busy. And when its cleared, it wont be added to the event queue anymore, when the timeout is executed after delayed 1004ms.
No.
Ignoring the fact there is no clearTimeOut function (it's clearTimeout) and it's being called with clockID, not timeOutID), all of these statements will be run sequentially; any tasks that setTimeout and friends might run will be only run after the current synchronous block of JavaScript is run, i.e. the sequence would be something like
[frame]
start()
setTimeout(...)
clearTimeout(...)
[frame]
(this is where timeout functions could be run)
I have created a JavaScript version of the Little Man Computer based on the Java one at http://www.atkinson.yorku.ca/~sychen/research/LMC/LMCHome.html
I have it working in by stepping through each instruction. I have a function called stepCode() that does this.
What I want is a function that will run the program, pausing for a second between each step until the simulated program ends.
The code I have is this:
function runProgram()
{
var milliseconds = 1000;
var timeOut;
programRunning = true;
while(programRunning)
{
timeOut = setTimeOut(stepCode(), milliseconds);
}
}
This seems does not work. It still performs all the stepCode() calls one after the other very quickly. I want to pause between each stepCode() call.
I'm obviously doing something wrong. Any ideas?
You should use setInterval instead of setTimeout. Additionally, you need to reference the function, not call the function:
var timeOut; // global timeout variable to ensure both methods have access to it.
function runProgram() {
var milliseconds = 1000;
timeOut = setInterval(stepCode, milliseconds); // use setInterval instead of setTimeout
}
function stepCode {
// ... code processing here ...
// I assume you are setting programRunning to false at some point in this method.
// Instead of setting programRunning = false, you would do:
clearInterval(timeOut);
// Note, if you only have one timeout interval set, you can use clearInterval();
}
setInterval will cause the stepCode function to run every 'milliseconds' until you call clearInterval(timeOut);; setTimeout will only queue it up once. Anything that is queued via setTimeout will not execute until the current flow of code has been completed. As a result, programRunning will run and queue up several setTimeout executions. Once the programRunning variable hit false, the current code flow will finish and ALL of the queues will wait 1 second, and effectively execute all at the same time, or in rapid succession.
When you pass in a method call (e.g. stepCode()), it will call the method. You have to pass a reference to the function stepCode (notice no parens), to ensure that it knows what to run each time it executes.
This Fiddle Demo simulates a counter, which is common thing people attempt to execute using setInterval. It demonstrates the basic concept and use of setInterval.
In addition to suggested setInterval use that will call stepCode at 1 second intervals until cleared (or until the page is reloaded), and correction of removing () after stepCode that results in immediate stepCode executon, you can still use setTimeout if they are chained as shown below. Depending on what stepCode does and how long it takes, this solution has an advantage of ensuring that there is 1 second of idle time between the end of the previous and the beginning of the next stepCodes.
var milliseconds = 1000;
function runProgram()
{
programRunning = true;
stepCodeWrapper();
}
function stepCodeWrapper() {
if (programRunning) {
stepCode();
setTimeOut(stepCodeWrapper, milliseconds);
}
}
Just try with:
timeOut = setInterval(stepCode, milliseconds);
Bic, thanks for your swift response. You are correct about the programRunning flag being set to false inside the stepCode() function. I've set it as a global variable so that I could possibly halt the program by pressing a button, but thats another problem.
Tried both setInterval and setTimeout. You are right about it repeatedly calling the function. Using either method locks up the browser with repeated function calls. This is probably as its in a while loop. I cannot think of another was to repeatedly call the stepCode() function otherwise.
I sort of understand the difference between setInterval & setTimeout. Thanks, and I understand that would make the while loop redundant, but then how to stop it calling the stepCode function when the programRunning flag is set to false?
I have a flurry of interrupts coming into a handler and I don't want to service them until 5ms have passed since the last interrupt, indicating the flurry is over.
My thought was to call setTimeout(LookAtInterrupts, 5) each time the handler is entered, but I don't see in the setTimeout() documentation that it will cancel a pending scheduled call if it's called before that execution occurs.
Is that, in fact, what it will do? I don't want to get called 5ms after every handler interrupt, just the last one.
No, it won't - you can have as many pending timeouts as you want.
The function returns a key that you can use to cancel a timeout later:
var key = setTimeout( ... );
Then to cancel it later:
clearTimeout(key);
Calling clearTimeout() with an already-expired key is not an error, so you don't have to worry about synchronization problems.
setTimeout will not reset itself.
You can reset a timeout manually by
var timeout = setTimeout(...);
clearTimeout(timeout);
A setTimeout() won't cancel any previous timeouts implicitly.
However, you can achieve that by storing the identifier in a variable and clearing that each time.
var timeoutId = null;
var yourFn = function() {
clearTimeout(timeoutId);
timeoutId = setTimeout(fn, 5);
};
You need to store a reference. setTimeout result can be stored and cleared later on.
For a "resettable" setTimeout:
// first assign it
var timeout = setTimeout(function(){
foo();
}, 50);
// then look for an existing assignment before re-assinging
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function(){
bar();
}, 50);
References:
setTimeout
clearTimeout
As an aside, be careful when setting a timeout < 5ms. Though HTML5 is supposed to support 4, I doubt you're actually getting anywhere close to that (w/ cost of spinning up the timeout).
Store reference to that setTimeout call in a variable, and after each successfull interrupt, before creating timeout, cancel the previous timeout,
var tv = null;
function interrupt(){
if(tv !== null){
clearTimeout(tv);
}
tv = setTimeout(LookAtInterrupts,5)
}
function LookAtInterrupts(){
}
By this, you'll guarantee that only the last interrupt will continue execution in 5ms intervals. I hope that was clear.
While you can implement this yourself, a more practical solution would be to grab underscore.js and use it's debounce function (see http://underscorejs.org/#debounce).
Then you can do:
var lookAtInterrupts = _.debounce(handleInterrupt, 5);
the resulting function will only run at most once every 5 ms.
When setTimeout() is executed it schedules one call to your binded function().
If you want to cancel it you have to get ID returned by setTimeout() and clear as:
var timeOutID = setTimeout( LookAtInterrupts, 5 );
(...)
clearTimeOut( timeOutID );
How can i stop a interval in javascript?
why does the interval not stop?
setInterval(alarm, 500);
window.clearInterval(alarm);
also tried:
window.setInterval(alarm, 500);
window.clearInterval(alarm);
always the same problem :(
still doesn't work:
var switc = 1;
getValue();
function getValue (){
if(switc == 1){
var myTimer = window.setInterval(alarm, 500);
}
else if(switc == 0){
window.clearInterval(myTimer);
}
}
function alarm(){
console.log("test");
}
When you call setInterval it returns a integer that you use to cancel the event. Store that into a variable and use that variable to cancel the event.
var myTimer = window.setInterval(alarm, 500);
window.clearInterval(myTimer);
EDIT:
Your code does not work since myTimer is a local variable and is reset every single time you call the function!
Make it global.
var myTimer = null;
function getValue (){
if(switc == 1){
myTimer = window.setInterval(alarm, 500);
}
...
MDN Docs: window.setInterval
Calls a function or executes a code snippet repeatedly, with a fixed time delay between each call to that function.
Syntax
var intervalID = window.setInterval(func, delay[, param1, param2, ...]);
var intervalID = window.setInterval(code, delay);
where
intervalID is a unique interval ID you can pass to clearInterval().
func is the function you want to be called repeatedly.
code in the alternate syntax, is a string of code you want to be executed repeatedly (using this syntax is not recommended for the same reasons as using eval())
delay is the number of milliseconds (thousandths of a second) that the setInterval() function should wait before each call to func. As with setTimeout, there is a minimum delay enforced.
Note that passing additional parameters to the function in the first syntax does not work in Internet Explorer. If you want to enable this functionality on that browser you must use a compatibility code (see the Callback arguments paragraph).
That code evinces a misunderstanding of the API. The setInterval() function takes two arguments: a function to call, and a number representing the number of milliseconds between calls. The function returns a token (a number) that identifies that particular interval timer. The token can be passed to clearInterval() to cancel the timer.
You are tring to clear an non existent interval. Assign the id returned by setInterval() to an variable and use it in clearInterval().
In your case alarm is the function that executes and its not the intervals id
var interval = setInterval(alarm, 500);
clearInterval(interval);
var timer = setInterval(alarm, 500);
Window.clearInterval(timer);
function alarm() {
// Do stuff
}
You need to save the handle of the interval to a variable so you can reference it later when you want to clear/stop it.
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);
})
})();