I have two functions on my page that I need to call periodically, but in a certain way only.
function_a needs to be run periodically when the page loads, until data is available and downloaded.
After this point, function_b then needs to run periodically forever.
I can easily do...
setInterval(function_a, 1000);
setInterval(function_b, 5000);
But this will run both functions from the start of page load and forever.
How can I stop function_a running once I have determined that it is not needed anymore, and only start function_b running after this point?
I can put checks within the function_a and function_b code so that they dont execute if not needed, but it seems very wasteful to still call them continually when they are not needed.
function_a(){
if (needed) { code here... }
}
function_b(){
if (needed) { code here... }
}
There must be a better way than that?
Instead of a setInterval here, setTimeout will work far better.
function a() {
//do stuff
if(condition) setTimeout(b, 5000)
else setTimeout(a, 1000)
}
function b(){
//do stuff
setTimeout(b, 5000)
}
a()
This way, the function will execute and schedule itself to run again on the desired interval. This is similar to the way requestAnimationFrame is used for creating animations.
You can assign a variable to setInterval() call and use clearInterval()
let a = setInterval(function_a, 1000);
function_b() {
if (a_is_not_needed) { clearInterval(a) }
}
Use clearInterval() to stop a function called in a setInterval()
var needed = false;
var f1 = function(){
console.log("Fct1");
if(needed){
setInterval(f2, 5000); // start f2 when f1 is finish
clearInterval(interval); // stop to call periodically f1
}
}
var f2 = function(){
console.log("Fct2");
}
var interval = setInterval(f1, 1000);
Try this fiddle and open console to see the result
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 understand that Javascript does not have a delay(500) method, which would delay execution for 500 milliseconds, so I have been trying to get around that by using setTimeout and setInterval.
for(var i =0; i< 10; i++){
/* Animation Code */
var doNothing = function(){var m =5;}
setTimeout(doNothing, 50);
}
However, this does not seem to work. I essentially want some code that stops the execution for n milliseconds and then continues execution.
Practically speaking, you can't do this. Deal with it and find a callback-based way instead. Typically this means putting everything that should happen after the delay in the callback itself.
For example, you can't do this to make baz wait:
foo();
setTimeout(function() {
bar();
}, 500);
baz();
so you do the only thing you can:
foo();
setTimeout(function() {
bar();
baz();
}, 500);
The setInterval() Method wait a specified number of milliseconds, and then execute a specified function, and it will continue to execute the function, once at every given time-interval.
Syntax
window.setInterval("javascript function",milliseconds);
The window.setInterval() method can be written without the window prefix.
The first parameter of setInterval() should be a function.
How to Stop the Execution?
The clearInterval() method is used to stop further executions of the function specified in the setInterval() method.
Syntax
window.clearInterval(intervalVariable)
The window.clearInterval() method can be written without the window prefix.
To be able to use the clearInterval() method, you must use a global variable when creating the interval method:
myVar=setInterval("javascript function",milliseconds);
Then you will be able to stop the execution by calling the clearInterval() method.
good refrence
If you came from the language/framework/API background, where you could suspend the execution with something like Sleep, or process user input synchronously with something like DoEvents, it won't work in JavaScript.
There is no way you can block the JavaScript event loop with something like this, for a good reason: UI responsiveness. In JavaScript, everything is asynchronous. You can use setTimeout to do something upon a timer event, but the user is still able to access the UI between the timer events or even navigate away from the page.
To address your code fragment, what you are looking for is called an asynchronous state machine. It allows to preserve the state of the code between stop/continue (in your case, it's the state of the animation, although i variable is also a part of it):
(function()
{
var i = 0;
var nextStep = function()
{
if (i<10)
{
/* Animation Code */
i++;
setTimeout(nextStep, 500);
}
}
nextStep();
})();
It will be much easier to code when all browsers support the new yield keyword:
http://pag.forbeslindesay.co.uk
On a side note, some other answers suggest using setInterval. There is a subtle but important difference between delay and interval. Delay is the time between two steps. Interval is the time since the previous step started. If each step of animation takes 200ms, and you use the interval of 500ms, the actual delay between two steps will be 300ms, not 500ms as probably expected.
setInterval() - executes a function, over and over again, at specified time intervals
To pass a function as a string, be sure to append the function name with parentheses.
window.setInterval("someFunction()", 5000);
When passing a function pointer, do not include the parentheses.
window.setInterval(someFunction, 5000);
var timer_id=setInterval(doNothing,500);
If you want to stop the execution
make the timer_id variable global
clearInterval(timer_id);
Much cleaner and readable code would be if you use RxJS
Here is an example:
Rx.Observable
.interval(1000)
.take(10)
.subscribe((x) => console.log(`${x}: ${new Date().toLocaleTimeString()}`))
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.lite.min.js"></script>
interval - is a time delay between your animation calls. In my example
it's 1000ms
take - number of times to execute subscribe - is function
that will be called every 1000ms for 10 times (in your case it will be
your animation code)
Here some something that could help.
function delay( s , callback )
{
var fct_ref = "tmp_" + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 6).toUpperCase();
var tmp_fct = ( callback !== undefined ) ? callback.toString().match(/^[^{]+\{(.*?)\}$/)[1] : "";
document.getElementsByTagName("body")[0].insertAdjacentHTML("beforeend","<div id='"+fct_ref+"' style='background-color:transparent;color:transparent;position:absolute;top:"+window.scrollY+"px;left:"+window.scrollX+"px;opacity:1;transition:all "+s+"s'>-</div>");
var func = new Function("return function transition"+fct_ref+"(e){ e.target.removeEventListener('transitionend' , transition"+fct_ref+", false ); "+tmp_fct+" ; document.getElementById('"+fct_ref+"').parentNode.removeChild(document.getElementById('"+fct_ref+"')); };")();
document.getElementById(""+fct_ref).addEventListener("transitionend", func , false );
document.getElementById(""+fct_ref).offsetHeight;
document.getElementById(""+fct_ref).style.opacity="0";
}
delay(1, function() { console.log("ANIMATION_1"); } );
delay(3, function() { console.log("ANIMATION_3"); } );
delay(5, function() { console.log("ANIMATION_5"); } );
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.
I wont to run a block of code in a certain amount of time and then when done, carry on with another block of code.
Using the setTimeout() is probably what you want. For example...
<script type="text/javascript">
function YourFunction()
{
alert('Hello Stackoverflow');
}
window.setTimeout(YourFunction, 1000);
</script>
Hope it helps
This is how you would do it, using the setTimeout function, which takes code to call as the first argument and how much time it should wait before calling it (in milliseconds) as the second argument:
function callWhenDone() {
// code to call when timeout finishes
}
setTimeout(function() {
// initial code to run
callWhenDone();
}, 5000); // 5000 = run in 5 seconds
Because of the nature of Javascript you have to encapsulate the code you want to run after the timeout is finished in its own function, otherwise it would be run before the timeout is finished. This is, in essense, a callback, and it is a big part of the event-based nature of Javascript.
You'll want to use the setTimeout() function.
setTimeout - executes code after a time interval
clearTimeout - cancels the setTimeout()
More details here.
Use setTimeout.
setTimeout(function() {
// code here
// you can use it recursively
// setTimeout(...);
},
1000 // 1000 miliseconds (= 1 second)
);
and setInterval is like setTimeout, except it repeats a code repeatedly.
<script type="text/javascript">
var timer = setInterval("firstFunction()","1000"); //every second call firstFunction()
var i = 0;
function firstFunction()
{
//first code
i++;
if(i == 3)
{
clearInterval(timer);
secondFunction();
}
}
function secondFunction()
{
//second code
alert("done!");
}
</script>
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);
})
})();