I'm trying to run a function every 5 seconds using JavaScript using a recursive setInterval function.
The following code just logs "started" as fast as possible and then crashes the browser. Why is this not running every 5 seconds?
function five() {
console.log("five");
setInterval(five(), 5000);
}
five();
Don't use setInterval this way. Use setTimeout. By calling setInterval, you create a UNIQUE timer every time the function is called. SetTimeout would create one timer that ends, and then creates a new timer.
You should also change the way you reference five. five() executes the function immediately. Just five passes a function reference, so do it as you see below.
function five() {
console.log("five");
setTimeout(five, 5000);
}
five();
Of course, you can always pass the function call as a string to be evaluated:
setTimeout("five()", 5000); // note the quotes
But this is generally considered bad practice.
You're calling five immediately, instead of merely passing it in:
function five () {
console.log("five");
}
setInterval(five, 5000);
/* ^ */
Change this line:
setInterval(five(), 5000);
like this:
setInterval(five, 5000);
But seems like what you really need is:
setTimeout(five, 5000);
So your code will look like:
function five() {
console.log("five");
setTimeout(five, 5000);
}
five();
The reason of crashing it is that you are calling the function five. Instead of that you should pass it as parameter.
setInterval(five, 5000);
Related
I have got a problem with my clearInterval method.
I learn about JS in depth at FrontendMasters and there is an exercise where you need to use setInterval and log a string at every second and then run clearInterval after 5 seconds. I have access to the right solution but I would like to know why my solution is not working to get better understanding. The console.log('clear called', func); runs after 5 seconds and log the clear called string and the function body. I have tried to use setTimeout to wrap wrapper.stop() but it did not work that way either. I have used closures to try to solve the exercise. Here is my script.
function sayHowdy() {
console.log('Howdy');
}
function everyXsecsForYsecs(func, interval, totalTime) {
function clear() {
console.log('clear called', func);
clearInterval(func);
}
return {
start() {
setInterval(func, interval);
},
stop() {
setTimeout(clear, totalTime);
}
}
}
const wrapper = everyXsecsForYsecs(sayHowdy, 1000, 5000);
wrapper.start();
wrapper.stop();
Thanks
clearInterval does not take a function but a timer id which gets returned when using setInterval (so that you can set multiple timers onto the same function, and cancel them individually). To use that, declare a local variable inside everyXsecsForYsecs
var timer;
Then assign the timer to it:
timer = setInterval(func, interval);
Then you can clearInterval(timer).
I'm trying to make the top row of a table delete itself, every 5 seconds, using javascript. My javascript looks like this:
setTimeout(function(){
document.getElementById("myTable").deleteRow(0);
}, 5000);
which gets it to delete the top row after 5 seconds. Is there a way to reset the setTimeout to begin counting down again?
In this case it looks like you are looking for the functionality of setInterval:
var myTimer = setInterval(function(){
document.getElementById("myTable").deleteRow(0);
}, 5000);
If you would still like to use setTimeout you would want to call another setTimeout inside your function(){ ... }); that does the same thing. Basically have a function that keeps calling itself with a setTimeout like so:
(function loop() {
document.getElementById("myTable").deleteRow(0);
setTimeout(loop, 5000);
})();
Put it inside of a function and call it again.
function deleteRows(){
var t = setTimeout(function(){
document.getElementById("myTable").deleteRow(0);
clearTimeout(t);
deleteRows();
}, 5000);
};
You need to use setInterval instead of setTimeout .
Check the difference between them here: JavaScript Timing Events
setTimeout(function, milliseconds):
Executes a function, after waiting a specified number of milliseconds.
setInterval(function, milliseconds)
Same as setTimeout(), but repeats the execution of the function continuously.
Therefor, you can rewrite your code as following:
var timer = setInterval(function(){
document.getElementById("myTable").deleteRow(0);
}, 5000);
Then if you want to stop the execution of that timer function, you can use:
window.clearInterval(timer);
I would use setInterval() instead. Inside your callback function check for number of rows and if the row exists then delete it, if it doesn't remove time interval.
Reference: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval
JS Fiddle example: https://jsfiddle.net/n2yg4fv2/ (I used 1 second delay to make it faster)
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
I use setInterval to run a function (doing AJAX stuff) every few seconds. However I also have an other function also calling it.
setInterval(myFunc(), 5000);
function buttonClick() {
// do some stuff
myFunc();
}
Most of the time it works, however sometimes this function gets called twice at the same time resulting in receiving exactly the same result twice, something I don't want.
I think I have to use clearTimeout:
var interval = setInterval(myFunc(), 5000);
function buttonClick() {
clearTImeout(interval);
// do some stuff
myFunc();
interval = setInterval(myFunc(), 5000);
}
However this causes the function to halt. Since it gets called from an other function some code never gets executed. How can I prevent this?
however sometimes this function gets called twice at the same time resulting in receiving exactly the same result twice, something I don't want.
JavaScript on browsers is single-threaded (barring using the new web workers stuff, but that wouldn't apply here anyway). Your function will never get called while it's running. (But more below.)
In your various code quotes, you're calling myFunc where you mean to just be referring to it. E.g.:
var interval = setInterval(myFunc(), 5000);
should be
var interval = setInterval(myFunc, 5000);
// ^--- No parentheses
Your code cancelling the timeout will work if you correct that:
var interval = setInterval(myFunc, 5000);
function buttonClick() {
clearTImeout(interval);
// do some stuff
myFunc();
interval = setInterval(myFunc, 5000);
}
But there's no reason to do that, myFunc cannot get called while it's running anyway.
If myFunc is triggering something that will complete asynchronously (an ajax call, for instance), the above won't help (for the simple reason that myFunc will start the process and then return; the process will complete separately). In that situation, your best bet is to have myFunc schedule its next call itself:
function myFunc() {
// Do my work...
// Schedule my next run
setTimeout(myFunc, 5000);
}
...and not use setInterval at all.
I realize there's a couple of solutions already, but thought I'd show one that has a tad more than just "do this". I tend to learn by example, and thought I would extend the same practice. That being said, the demo is here but I'll try to explain as well.
// Here we assign the function to a variable that we can use as an argument to the
// setInterval method.
var work = function(){
// performing a very simple action for the sake of demo
$('#log').append('Executed.<br />');
};
// this is a variable that is essentially used to track if the interval is or is
// not already running. Before we start it, we check it. Before we end it, we also
// check it. Let's start off with it started though
var worker = setInterval(work, 5000);
// bind to the start button
$('#start').click(function(){
// Test: is the worker already running?
if (worker)
// Yes it is, don't try to call it again
$('#warn').text('Timer already running!');
else{
// no it's not, let's start it up using that function variable we declared
// earlier
worker = setInterval(work,3000);
$('#warn').text('Started!');
}
});
// bind to the stop button
$('#stop').click(function(){
// test: is the worker running?
if (!worker)
// no, so we can't stop it
$('#warn').text('Timer not running!');
else{
// yes it's working. Let's stop it and clear the variable.
clearInterval(worker);
worker = null;
$('#warn').text('Stopped.');
}
});
Unless myFunc returns a function I would do this (also use clearInterval in stead of clearTimeout):
var interval = setInterval(myFunc, 5000);
function buttonClick() {
clearInterval(interval);
// do some stuff
myFunc();
interval = setInterval(myFunc, 5000);
}
setInterval expects a function in its argument. You call a function by using myFunc(). so whatever is returned by myFunc was passed to setInterval which is probably not what you want.
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);
})
})();