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 );
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)
Is there a way to avoid the conflict between the delay and execution time if the time of execution was longer than the delay using setInterval()?
For example:
setInterval(function(){
// some code that takes 300 ms to be executed
// which it's longer than the delay 200 ms
}, 200);
I already found the alternate way, which is to use setTimeout() with recursion to ensure that the delay will start immediately after the function is executed, but my question is about setInterval(), not replacing it with setTimeout()
I'm not sure what is your concern.
Javascript is always single-threaded that means that in time of execution of the function called by setInterval no other function will be executed and no re-run of setInterval may happen!
Naturally if in your setInterval called function you use deferred calls you enable the function to finish and be executed again.
To protect against such problem you may use a simple semaphore like:
var inProcessing = false ;
setInterval(function(){
// some code that takes 300 ms to be executed
// which it's longer than the delay 200 ms
if (!inProcessing){
inProcessing = true ;
$http.get(...).then(function(){inProcessing = false;...},
function(){inProcessing = false;...});
}
}
}, 200);
You cannot do this using setInterval, only setTimeout. If your problem is the lack of easy cancellation of the setTimeout method, you can use the following:
var timeout = setTimeout(function runMe(){
// some code that takes 300 ms to be executed
timeout = setTimeout(runMe, 200);
}, 200);
// somewhere else
clearTimeout(timeout);
You can use a nested setTimeout instead of setInterval. Hope you enjoy !
https://javascript.info/settimeout-setinterval
I'm assuming you just want to postpone a cycle of setInterval if the code from a previous run isn't complete.
var starts = 0;
var ends = 0;
function myFunc () {
starts++;
//doStuff
ends++;
}
setInterval(function () {
if (starts === ends) {
myFunc();
}
}, 200);
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 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?
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);
})
})();