setInterval() - but run it only once - javascript

If I call the update function several times I get multiple instances of this interval running. How can I be sure that this only gets triggered once per idVar?
For example if I run this twice in a row with the same idVar I get two updates per second, where it should only be one.
If the idVar is different it should run multiple times. idVar is used in Update().
intervals[idVar] = setInterval(function() {
update();
}, 1000);

intervals[idVar] = setTimeout(function() {
update();
}, 1000);

If you really need to use setInterval and dont want to use setTimeout , you can clear it when you enter function
For example
var interval
interval = setInterval(function(){
clearInterval(interval)
//Your code
});

If you really want a new instance of the interval running for each unique idVar, you just need to check to see if you already have an instance of the interval running for the current idVar:
if (!intervals[idVar]) {
intervals[idVar] = setInterval(function() {
update();
}, 1000);
}

setInterval returns a timeoutID that is used to identify it.
To stop a setInterval you pass it's timoueID to clearInterval.
Explanation of why you get two intervals running
When you do this:
intervals[idVar] = setInterval(function() { update(); }, 1000);
intervals[idVar] = setInterval(function() { update(); }, 1000);
What you are doing is:
call your first setInterval and setting intervals[idVar] to this first setInterval's timeoutID
call your second setInterval and overwrite the value stored in intervals[idVar] with the timeoutID of your newly called
setInterval
Result: Two seperate intervals, with intervals[idVar] storing the timeoutID of the second one called
setTimeout
setTimeout is like setInterval and actually uses the same pool of timeout IDs, but it is only invoked once after the specified delay.
Setting one interval (setTimeout or setInterval) per idVar
var idVar = setInterval(function() {
update();
}, 1000); // sets idVar to the timeoutID and starts the interval
}
intervals[idVar] = idVar; // assigns a property 'idVar' on `intervals`
// and sets the timeoutID as its value
// allows you to call clearInterval(intervals[idVar]);
However, without knowing exactly what your update() method is doing it is difficult to tell what the best solution would be here...

Related

Is it possible to vary the time interval while the timer is running in d3.js?

I want to be able to adjust the time interval between the callbacks. I'm using d3's interval in the following manner:
let timeInterval = 500;
d3.interval(callback, timeInterval);
Now, at some point during the execution, I want to be able to adjust the timeInterval's value (via user input) and have it reflect in the speed at which the subsequent callbacks will be executed.
Is this possible, and if so, how?
The easiest way to change an interval's behavior—including its timing—is calling the .restart() method on it. Since a d3.interval() is just a wrapped d3.timer() which is executed periodically it also features said .restart() method.
# timer.restart(callback[, delay[, time]]) <>
Restart a timer with the specified callback and optional delay and time. This is equivalent to stopping this timer and creating a new timer with the specified arguments, although this timer retains the original invocation priority.
This can be done along the following lines:
const callback = console.log;
const interval = d3.interval(callback, 500); // initial timing 500ms
interval.restart(callback, 1000); // updated timing 1000ms
<script src="https://d3js.org/d3.v6.js"></script>
d3.interval() apparently returns the timer object that was created.
You can stop the old timer and start a new one:
var intervalTimer;
// ... other code ...
intervalTimer = d3.interval(callback, 500);
// ... other code ...
intervalTimer.stop();
intervalTimer = d3.interval(callback, 100);
// ...

Wrong use of Javascript setInterval()

I have a function called using setInterval of JavaScript, which in some scenarios is called multiple times without the interval gap defined (I suspect this is because the intervals are not cleared properly and I'm creating multiple intervals, but I'm not sure).
I can not reproduce the problem locally.
The code uses Twirl but it's basically JS:
function refreshCheckInRequests() {
if (interval) { // If there is an interval running stop it.
clearInterval(interval);
}
jsRoutes.controllers.ExtranetSecuredController.findPendingCheckInRequests("#gymId").ajax({ // Ajax call using Play Framework
success: function (data) {
$("#checkin-request-container").html(data);
addRowListeners()
},
error: function (data) {
if (data.status == 401) {
errorSwitchGym("#Messages("extranet.switch.gym")");
//location.reload();
}
else {
unexpectedError(data)
}
},
complete: function() {
interval = initInterval(); // At the end of the call init the interval again
}
});
}
function initInterval() {
return setInterval(function () { refreshCheckInRequests(); },
20000);
}
var interval;
refreshCheckInRequests();
$("#checkin-request-refresh").click(function (event) {
refreshCheckInRequests();
event.preventDefault();
});
I could use setTimeout instead because at the end, I always call refreshCheckInRequests once, I stop the interval, and at the end I create a new one.
If I use timeout I have to call again my function at the end of the execution of the callback of timeout (like I'm doing right now). If something goes wrong, my callback will never be called again.
Anyway, I would like to know what's going on here. Am I missing something? Am I doing something wrong? Any suggestions?
You're clearing the current interval every time refreshCheckInRequests is called, but there is a delay between when refreshCheckInRequests is called and the new interval is assigned. Because refreshCheckInRequests also runs when an element is clicked, the following scenario could result in an unterminated interval:
User clicks, current interval is cleared, asynchronous findPendingCheckInRequests runs
User clicks again, no interval currently exists (nothing to clear), another asynchronous findPendingCheckInRequests runs
Response from first findPendingCheckInRequests comes back. complete handler runs, interval is assigned to the new interval
Response from second findPendingCheckInRequests comes back. complete handler runs, interval is assigned to the new interval over the old interval
The first created interval remains running, but there no longer exists a reference to it, so that first interval continues repeating forever.
So, try clearing the interval at the moment you reassign interval, ensuring that every new interval will always clear the old one, if an old one is running:
complete: function() {
clearInterval(interval);
interval = initInterval();
}

Reset setTimeout after timer expires

I have an ongoing while loop. In the while loop, there is a setTimeout(). I want to reset the timer AFTER the timer expires. In other words, when timer expires, it should do some specified actions, and then freshly start the timer again.
For example, in the following code, %%--Hi--%% should be printed only ONCE in 5 seconds. However, after 5 seconds, %%--Hi--%% is printed continuously. I tried clearTimeout but it looks like that clearTimeout can stop timer only before timer expires.
while(){
var timeoutHandle = setTimeout(function() {
console.log("%%--Hi--%%");
clearTimeout(timeoutHandle);
},
5000); //5 sec
}
Help please! Thanks!
It's not the timeout that's tripping you up, it's the infinite while loop. You're effectively creating thousands of timeouts every second. Moving the timeout outside of the infinite loop should solve your problem.
function timedAction() {
// your timed actions to be invoked every 5 seconds
setTimeout(timedAction, 5000); // start the next timeout
}
setTimeout(timedAction, 5000); // start the first timeout
while() {
// your continuously executing actions
}
There is no need to clear a timeout after it expires.
Alternatively you could also use setInterval, simplifying your code as follows:
function timedAction() {
// your timed actions to be invoked every 5 seconds
}
setInterval(timedAction, 5000); // start the interval
while() {
// your continuously executing actions
}
try this code:
logFun();
function logFun() {
console.log("%%--Hi--%%");
setTimeout(logFun, 5000);
}
or, you can try setInterval:
setInterval(function () {
console.log("%%--Hi--%%");
}, 5000);
The setTimeout method does not act like a sleep statement. Your while loop will continue to iterate continuously regardless of what time interval you set in the setTimeout method.
You should remove the while and simply use setInterval(). (Mentioned in yibuyisheng's answer. +1)
var myInterval = setInterval(function () {
console.log("%%--Hi--%%");
}, 5000);
If you want to stop the interval, run the following:
clearInterval(myInterval);
Your problem is that setTimeout is an asynchronous function, so your code doesn't wait for it to finish before looping again. To get around this you have to create your new timer inside the previous timer.
Likewise you have to call any actions you want to execute from inside the timer and can't just call them from in the while loop, because they won't wait for the timer to finish.
function logFun() {
console.log("%%--Hi--%%");
// execute actions
setTimeout(logFun, 5000);
}
This is what yibuyisheng has done with his answer that just showed up. (Still posting because the answer was not explained.)
Alternatively, if you must create the setTimeout() from the while loop, you could have a boolean (true/false) lock it. This is not as clean as yibuyisheng's answer, but it also allows you to add as much logic as you'd like to control enabling and disabling the timeout.
Example:
window.isTimeoutLocked = false;
while(true) {
if (!window.isTimeoutLocked) {
var myFunction = function () {
console.log("%%--Hi--%%");
//The timeout has fired. Unlock it for the next one.
window.isTimeoutLocked = false;
}
window.setTimeout(myFunction, 5000);
//Timeout is queued. Lock this code until the timeout fires.
window.isTimeoutLocked = true;
}
}
Also, I doubt that an infinite while loop is best for your upstream code. There is probably a callback that you can hook into, like requestAnimationFrame or some relevant event.

Run a Javascript in timed intervals?

How can I run a Javascript function with per-set time delays, without using any framework?
I have a Ajax script which will fetch the no of online users from server. This script i want to run in a regular timed delays.
Thanks in advance.
The simplest way would be with setInterval:
setInterval(function() {
console.log("run every second");
}, 1000);
This will run the given code at the specified time interval over and over.
var interval = window.setInterval(function() {
console.log("foo");
}, 1000);
And stop
window.clearInterval(interval);
You can use setInterval to do this.
See: https://developer.mozilla.org/en/DOM/window.setInterval
var int = self.setInterval(askQuestion,1000);
function askQuestion() {
// do something... code to be implemented.
}
Will be call askQuestion() every 1000 milliseconds (1 seconds) for example..
<script>
var intervalVariable=setInterval(function(){
//Your operation goes Here
},1000); // executes every 1000 milliseconds(i.e 1 sec)
function stopTimer()
{
clearInterval(intervalVariable); // To clear TimerInterval/stop the setInterval Function
}
</script>

Run a function in timeout looping

I have the following code:
// After 8 seconds change the slide...
var timeout = setTimeout("changeSlide()", 8000);
$('div.slideshow').mouseover(function() {
// If the user hovers the slideshow then reset the setTimeout
clearTimeout(timeout);
});
$('div.slideshow').mouseleave(function() {
clearTimeout(timeout);
var timeout = setTimeout("changeSlide()", 8000);
});
What I want to happen is make the function changeSlide run EVERY 8 seconds in a loop unless someone hovers the slideshow div. When they remove the cursor then do the timeout again!
However the loop only happens once and the hover doesn't stop the timeout or start it again :/
EDIT:
This loops great but the hover on and off causes the function to run multiple times:
// After 8 seconds change the slide...
var timeout = setInterval(changeSlide, 2000);
$('div.slide').mouseover(function() {
// If the user hovers the slideshow then reset the setTimeout
clearInterval(timeout);
});
$('div.slide').mouseleave(function() {
clearInterval(timeout);
var timeout = setInterval(changeSlide, 2000);
});
You have a couple issues here. First off, when you set a timeout, you need to store the return of that function call into a variable if you potentially want to stop it.
var slide_timer = setTimeout(changeSlide, 8000);
Second, when you call clearTimeout (rather than clearInterval), you need to pass it an argument. What argument? That variable you stored when you called setTimeout
clearTimeout(slide_timer);
Third, when you use setTimeout, it only fires once. setInterval will continue to fire, then you'd use clearInterval to stop it.
There is an issue in timing with using intervals rather than timeouts. The browser treats them subtly differently, and it may be important to your code to know the difference and use the proper method. If you use intervals, since they only fire once, you'll have to re-establish the timeout every time it fires.
var slide_timer = setTimeout(function () {
changeSlide();
var slide_timer = setTimeout(changeSlide, 8000);
}, 8000);
OR
var slide_timer = setTimeout(changeSlide, 8000);
...
function changeSlide() {
... your code ...
var slide_timer = setTimeout(changeSlide, 8000);
}
(I prefer the former method)
And lastly, whether you use timeouts or intervals, don't pass a string to setTimeout, pass a function reference. See the sample code above, or like this:
var slide_timer = setTimeout("changeSlide()", 8000); // <--- DON'T
var slide_timer = setTimeout(changeSlide, 8000); // <--- DO
var slide_timer = setTimeout(function () { // <--- DO
changeSlide() ;
// other script
}, 8000);
Putting it all together:
// After 8 seconds change the slide...
var slide_timer = setTimeout(changeSlide, 8000);
$('div.slideshow').hover(function() {
// If the user hovers the slideshow then reset the setTimeout
clearTimeout(slide_timer);
}, function() {
slide_timer = setInterval(changeSlide, 8000);
});
Documentation
clearTimeout - https://developer.mozilla.org/en/DOM/window.clearTimeout
setTimeout - https://developer.mozilla.org/en/DOM/window.setTimeout
clearInterval - https://developer.mozilla.org/en/DOM/window.clearInterval
setInterval - https://developer.mozilla.org/en/DOM/window.setInterval
SO answer discussing the subtle difference between intervals and timeouts - https://stackoverflow.com/a/7900293/610573
When you specify setTimeout (or setInterval), it returns a value that is then used for clearTimeout and clearInterval. Correct usage is as follows:
var timeout = setTimeout(changeSlide, 8000);
clearTimeout(timeout);
Also note I am using clearTimeout, not clearInterval.
You'll also notice that I did not put quotes around 'changeSlide', and that I dropped the parens. When passing a string to setTimeout, eval() is used. eval() is, in general, recommended to be avoided. So, instead, we pass it the direct reference to the function (without quotes). We do not use parens, because that would actually call changeSlide() right away, instead of deferring execution to setTimeout (and would pass, as an argument to setTimeout, the result of changeSlide())
EDIT: To get it to run continously, you have to call setTimeout again after each changeSlide call. setTimeout runs once. As an alternative, you can use setInterval, which automatically repeats. The one caveat to setInterval is that if the interval is too short and the callback it calls takes a long time to run, you can end up with a bunch of intervals queued up to execute one after another, without delay. An 8 second interval would likely not face this problem.
EDIT 2:
var timeout;
var changeSlide = function(){
// do something to change slides
clearTimeout(timeout);
timeout = setTimeout(changeSlide, 8000);
}
// queue up the first changeSlide, all others happen inside changeSlide
timeout = setTimeout(changeSlide, 8000);
$('div.slideshow').mouseleave(function() {
clearTimeout(timeout);
var timeout = setTimeout(changeSlide, 8000);
});
I think you need setInterval and not setTimeout, since:
setTimeout(expression, timeout); runs the code/function once after the timeout
setInterval(expression, timeout); runs the code/function in intervals, with the length of the timeout between them
In the end this worked the best (but I won't accept this as my answer as it was others who helped me get to this point)
// After 8 seconds change the slide...
var slide_timer = setInterval(changeSlide, 2000);
$('div.slideshow').hover(function() {
// If the user hovers the slideshow then reset the setTimeout
clearInterval(slide_timer);
}, function() {
slide_timer = setInterval(changeSlide, 2000);
});
Your issue may be the mouseover event. The mouseover event bubbles, so if you have a nested HTML structure, then the event may be called more than once. If you are using jQuery, you should use the mousenter event, which will only get called once for the element.
On a different note, instead of using setInterval use a setTimeout pattern. Something like this:
//Immediately Invoked Function Expression that gets called immediately
(function() {
//Make the initial call to your setTimeout function
repeat();
//Function will constantly be called
function repeat() {
setTimeout(function() {
//(Put your conditional logic here)
console.log('test');
repeat();
}, 2000);
}
})();

Categories