JavaScript: window.setTimeout(), force early expire - javascript

I have a <div> on my page that refreshes automatically every two minutes with updated log entries. When I first load my webpage, I call the following function.
function getLogs() {
var filter = $('#filter').val();
$.get("index-ajax.asp", { queryType: "getLogs", filter: filter,
uTime: new Date().getTime() },
function(data){
$("#logEntries").html(data);
window.setTimeout("getLogs()",120000);
});
}
I know the above code could be cleaner with window.setInterval(...); but I just like the control of window.setTimeout(...);.
My question, is it possible to cancel the next timeout execution? In the event that I change the filter, I'd like to cancel the next timeout, and call the function right away, which would reschedule the timeout function. Is there a better way to achieve that result?
Note that the above code is in jQuery.

Yes, use clearTimeout.
Ex:
var clr = window.setTimeout(getLogs,120000);
The when you wan to clear it:
clearTimeout(clr);

setTimeout returns a timerID that you can pass to clearTimeout:
// Note we are passing the *function* rather than a string
// Also note the lack of () - we are *not* calling the function
// setTimeout will do that for us
var timerID = setTimeout(getLogs, 120000);
// Fake condition - we cancel the timer if the timerID is even
if (timerID % 2 === 0) {
clearTimeout(timerID);
}

You could always define a new variable based on a filter value and if that filter value is set, use a while statement to omit the timeout:
if(filter == "whatevs"){
var i=true;
}
function(data){
$("#logEntries").html(data);
while(i!=true){
window.setTimeout("getLogs()",120000);
}
}

Related

How to make the refresh frequency of setTimeout a variable?

I want a function I am writing to call itself automatically. I want to be able to parse the frequency at which it calls itself via the first time I parse it. It would then use that same value internally with the JS setTimeout() function to call itself repeatedly again at the same frequency.
So you can see what I have in the sample below:
function testFunction(refreshFrequ){
setTimeout(function() {
console.log("frequency: "+refreshFrequ);
testFunction(refreshFrequ);
}, refreshFrequ);
}
// run the 1st time
testFunction(5000);
The problem is that this doesn't work as from the second time it runs onwards the parsed timeout isn't evaluated. The console output gives a clue to what's going on here:
frequency: undefined
How would I get this working, nothing so far has helped.
Try Window setInterval() Method instead. Also see this answer and this answer for more information.
var autoInterval;
var elapsed = 0;
function myStartFunction(refreshFrequ) {
if (!autoInterval) {
autoInterval = setInterval(function() {
elapsed++;
document.getElementById("txt").innerHTML = refreshFrequ * elapsed + " elapsed.";
console.log("frequency interval: " + refreshFrequ + " x " + elapsed);
}, refreshFrequ);
}
}
function myStopFunction() {
if (autoInterval) {
clearInterval(autoInterval);
autoInterval = null;
elapsed = 0;
document.getElementById("txt").innerHTML = "Interval was reset.";
console.log("interval stopped");
}
}
myStartFunction(5000);
<p>The setInterval() method has started automatically.</p>
<button onclick="myStartFunction(1000)" title="Start with 1000 ms interval. Clicking this button while the event is active should not create a new interval instance.">Start</button> <button onclick="myStopFunction()" title="Click to stop and clear the interval instance.">Stop</button>
<p id="txt">0 elapsed.</p>
Edit: Although there was no mention of the potential duplicate function calls, the other answer should be taken into consideration, especially if the event can arbitrarily be executed. The if statement was imposed in order to prevent duplicate events from being stacked up against the original instance; otherwise, each additionally executed function would result in a unique instance, which could then further create unstoppable multiple events, so I must give credit where credit is due. Kudos to Tymek!
You might want to use setInterval instead.
var testFunction = (function () { // This will "build"/"enclose" our function
var handle = null; // ID of the interval
return function (freq) {
if (handle !== null) clearInterval(handle);
handle = setInterval(function() {
console.log("frequency: " + freq);
}, freq);
};
})();
With this if you re-initialize interval, you will not create another instance of it (having 2 functions ticking).
You can learn more about setInterval at: https://www.w3schools.com/jsref/met_win_setinterval.asp
and more about how JavaScript functions works at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

setInterval(setTimeout) function for given invokes javascript

I need to invoke some function given number of times through given delays. How should I do - declare variable for timer and pass it to invoking function for stopping timer in some moment or in loop (n times) invoke setTimeout once ( or some another approach to skeep delay time once) or other.Thanks.
edit to fix syntax eror
var timerID = null;
var n = 5;
this.timerID = setInterval(function(){
funcToInvoke(n,timerID){
if(invokeNumber == n){
clearInterval(timerID);
return;
}
else { do something}
}
},delay)
Yes, the approach is common and better than calling setTimeout in a loop (with a fixed number of times). It is more performant than that and also more flexible, because the interval will be stopped dynamically (might check for a future condition).
However, your code is a bit messy. Fixed:
// Assuming we a have
// n
// delay
// funcToInvoke
// and execute in context of some object
var that = this,
numberOfInvokes = 0;
this.timer = setInterval(function() {
// "this" points to the global object
if (numberOfInvokes == n)
clearInterval(that.timer);
else
funcToInvoke(numberOfInvokes);
numberOfInvokes++;
}, delay);
Your current method has a syntax problem, you can't have a function parameter like this.timerID). In fact, you should remove the whole funcToInvoke declaration, and declare n and timerID as local variables, so they will be available to the closure. Like this:
// Don't forget to define n here!
var n = 5;
// Change timerID to local var instead of property
var timerID = null;
timerID = setInterval(function(){
if(invokeNumber == n){
clearInterval(timerID);
return;
} else {
//do something
}
// You can setTimeout again anywhere in this function if needed
}, delay);
If you want an approximate delay, setInterval is probably ok. If you want a more precise interval, then repeated calls to setTimeout are better as you can adjust the length of time to the next call based on the time since the last call.
E.g. for a clock ticking every second, you can do repeated calls to setTimeout, setting the lag to just after the next full second.

Javascript function call into loop each time

I have function called rotator(id): this function animate div and I can called this function with different id for animate different elements
Actually I use 5 differents id , 1,2,3,4,5
And for call I need put :
rotador(1);rotador(2);rotador(3);rotador(4);rotador(5);
The problem it´s that I want to rotate in automatic mode. For this I think to use this
for (i=0;i<=5;i++) {
setTimeout(rotador(i),2000);
}
But it doesn't work because it animates all in the same time, no let firt execute the first and continue before of first go second , etc , etc and when go the end or number 5 start other time in one
My problem it´s this if you can help me THANKS !!! :) Regards
You are actually calling the rodator(i) function, and schedule for execution after 2 seconds the result of the rodator. In other words, your code is now equalent to:
for (i=0;i<=5;i++) {
var result = rotador(i);
setTimeout(result,2000);
}
You can accomplish this either by creating a function for the callback:
for (i=0;i<=5;i++) {
setTimeout((function(i){
return function(){
rotador(i);
}
})(i),2000 * i);
}
or you can call the next rodator in the rotador function itself:
var rotador = function(i){
// your code
if (i < 5) {
setTimeout(function(){rotaror(i + 1);}, 2000);
}
}
Note: the closure in the second example is needed to call the function with the correct value of i. We are creating an anonymous function, and create i as a local scope variable, which value won't be mutated by the outerscope changes. (we can rename i to n in the local scope, if this would be more readable). Otherwise the value of i will be 5 each time rotador is called, as the value of i would be modified before the actual function call.
since setTimeout() does not wait for the function to be executed before continuing, you have to set the delay to a different value for different items, something like 2000 * (i + 1) instead of just 2000
EDIT: yes, and you need the callback as Darhazer suggests
rotationStep(1);
function rotador(id)
{
console.log(id);
}
function rotationStep( currentId )
{
rotador(currentId);
var nextId = currentId<5 ? currentId+1 : 1;
setTimeout(function(){ rotationStep(nextId) },2000); //anonymous function is a way to pass parameter in IE
}
Use a callback:
setTimeout(function() {
rotador(i)
}, 2000)

Javascript functions through the url bar with a delay

So.. I have a webpage with a javascript function I wish to execute..
Not knowing javascript very well I exectue the function through the url bar..
javascript: Myfunct1();
javascript: Myfunct2();
Now what I really need to be able to do is a long sleep, execute the first function, sleep for a little, then execute the second function, then loop forever.. something like:
javascript: while(1) { Sleep(20000); Myfunct1(); Sleep(5000); Myfunct2() };
Obviously there isn't a 'Sleep' function.. and this is my problem.. After looking at various posts about 'setTimeout;, I tried that but have been unable to get it right.. was wondering if somebody would take pitty and a poor javascript simpleton and show me the way to do this?
have a look at setTimeout(). This will give you the delay you're looking for.
http://www.w3schools.com/js/js_timing.asp
Just pop this into your HTML before the </body> tag
<script type="text/javascript"><!--
setTimeout(function(){
Myfunct1();
setTimeout(function(){
Myfunct2();
},5000);
},20000);
--></script>
You can use setInterval in conjuction with setTimeout function:
setTimeout('Myfunct1(); setInterval("Myfunct1();", 25000);', 20000);
setTimeout('Myfunct2(); setInterval("Myfunct2();", 25000);', 25000);
This will accomplish the functionality like in your example without hanging the browser. Basicallly, it will Myfunct1() after 20s, and set it to run again 25s after that. Same thing is with Myfunct2(), except that it first run after 25s.
Here's a function that allows you to call alternating functions, waiting a specified amount of time between each invocation:
function alt(fn1, tm1, fn2, tm2) {
var curr, time;
(function next() {
curr = (curr === fn1) ? fn2 : fn1;
time = (time === tm1) ? tm2 : tm1;
window.setTimeout(function() {
curr();
next();
}, time);
})();
}
Use it like this:
alt(Myfunct1, 20000,
Myfunct2, 5000);
This will wait 20 seconds, then call Myfunct1, then wait 5 seconds and call Myfunct2, then wait 20 seconds and call Myfunct1 again, and so on.
Here's a general purpose version that accepts any number of function/timeout pairs:
function alt() {
var args = arguments;
(function next(i) {
if (i == args.length)
i = 0;
window.setTimeout(function() {
args[i]();
next(i + 2);
}, args[i + 1]);
})(0);
}
It's used the same way, but can accept more than two pairs:
alt(function(){console.log("1")}, 2000,
function(){console.log("2")}, 1000,
function(){console.log("3")}, 5000);
If this were real code there's a lot more you could do, like verify arguments and/or specify default timeouts when not provided for any of the given functions.

Interrupt jQuery delay function

I am working on a way to autocomplete function to navigate through steps of a form. Here is the code that when 5 characters are entered into an input, it then moves to the next element. My delay is working great, but I don't have a way to stop it from completing if characters get deleted after 5 characters are entered. It just fires off the focus right after that no matter what has changed in the input.
Any thoughts?
var delay = (function(){
var timer = 0;
return function(callback, ms) {
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
$('input').keyup(function(){
if($(this).val().length == 5) {
delay(function(){ $("#saveForm2").focus(); }, 2000 );
}
})
If you're looking for an easy way to associate a timeout instance with an element, consider using jQuery's .data() method.
Something like this.
$('input').keyup(function() {
var $th = $(this);
var data = $th.data();
if(data.timeout === undefined) {
data.timeout = null;
}
if ($th.val().length == 5) {
clearTimeout(data.timeout);
data.timeout = setTimeout(function() {
$("#saveForm2").focus();
}, 2000);
} else {
clearTimeout(data.timeout);
}
});​
I don't think the way you were using the closure was quite right. I think you would need to assign the handler to the element inside the closure as well, so it has a local reference to the instance.
EDIT: Made a little more efficient with earlier stored reference to data().
Each time you call delay(), you clobber your timeout handle, which means that you can't manage it after the fact. It also means that you're going to fire off a request every time you hit 5 characters, if I read that correctly. Try something like this:
var delayTimer;
var nextField = function() { $("#saveForm2").focus(); }
$('input').keyup(function(){
clearTimeout(delayTimer);
if($(this).val().length >= 5) {
delayTimer = setTimeout(nextField, 2000);
}
})
That'll a) fire off no more than 1 request unless you wait more than 2 seconds between keystrokes, and b) will cancel any pending request if you drop back under 5 characters before the timeout expires. As a bonus, it won't create a whole mess of anonymous functions.

Categories

Resources