I want implement function queue,where it should be executed based upon passed in time delay. If any of the function in the queue is invoked before the delay, then queue must not execute that function and should be moved to the next function in the queue.
For example:
function funQueue(message,date){
//logic
}
var fn1=funQueue("message1",new Date().getTime()+500)
var fn2=funQueue("message2",new Date().getTime()+1000)
var fn3=funQueue("message3",new Date().getTime()+2000)
fn2()
When it is executed like the above it should print.
message1
message3
please note message2 is not printed.
Thanks all,
Maybe a little something like the following, using setTimeout() and clearTimeout():
function funQueue(message,date){
var timeoutId = setTimeout(function() { // schedule a timeout
console.log(message) // that logs the message
}, date - new Date().getTime()) // at the specified time
return function() { // return a function
clearTimeout(timeoutId) // that cancels the timeout
}
}
var fn1=funQueue("message1",new Date().getTime()+500)
var fn2=funQueue("message2",new Date().getTime()+1000)
var fn3=funQueue("message3",new Date().getTime()+2000)
fn2()
Note that if you call funQueue() with a time that is in the past it will still call setTimeout(), which means the message would be logged immediately after the current code completes unless it is cancelled within the current code.
EDIT: I was asked in a comment to implement it without multiple simultaneous timeouts. The following is the first way that came to mind. I'm sure this could be tidied up, optimised, and/or completely rewritten in a better way, but it worked the first time I clicked "run" so I think it's a good enough starting place. I'll leave the explanation of how it works as an exercise for the reader...
var funQueue = function() {
var queue = []
var timeoutId
function setNext() {
clearTimeout(timeoutId)
if (queue.length > 0) {
timeoutId = setTimeout(function() {
console.log(queue.shift().message)
setNext()
}, queue[0].date - new Date().getTime())
}
}
return function(message,date){
var item = { message: message, date: date }
var i = 0
while (i < queue.length && date >= queue[i].date) i++
queue.splice(i, 0, item)
setNext()
return function() {
var i = queue.indexOf(item)
if (i != -1) {
queue.splice(i, 1)
setNext()
}
}
}
}()
var fn1=funQueue("message1",new Date().getTime()+500)
var fn2=funQueue("message2",new Date().getTime()+1000)
var fn3=funQueue("message3",new Date().getTime()+2000)
var fn4=funQueue("message4",new Date().getTime()+1500)
var fn5=funQueue("message5",new Date().getTime()+2000)
fn2()
Do something like this to check whether the time has passed or not
var timePassed;
function funQueue(message, date){
if(timePassed > date){
timePassed = new Date.getTime();
// Do stuff
}
}
Related
Here I have a piece of code that auto-executes every 2 seconds. However, the time it takes to execute function roll() varies due to the Internet connection's peaks and bottoms. I'm trying to make the function roll() execute itself automatically every 2 seconds, but the code must wait till the function is fully executed before proceeding and auto-executing again.
P.S. Any suggestions of a better title for this question would be appreciated.
var init = 0.01
var start = init
var $odds = $("#oddsOverUnder")
var $button = $("#roll")
var $bet = $("#bet")
function roll() {
$bet.val(start)
$button.click()
setTimeout(function() {
var tr = document.querySelector("#myBetsTable tr:nth-child(2)")
var cls = tr.getAttribute('class')
if (cls === 'success'){
start = init
$bet.val(start)}
else{
start = start * 2
$bet.val(start)
$odds.click()}
$button.click();
setTimeout(function() {
$button.click();
},1000);
},1000);
}
setInterval(roll, 2000)
Don't use setInterval. It will try to call a function after the elapsed time regardless whether it's finished or not. setTimeout is better, as you can control when it gets called. And you quite normally just call it at the end of a function (where it calls itself).
E.g.
function draw() {
// Some drawing here...
setTimeout(draw, 50);
}
So, when you call draw() above, it will do its operations, then wait 50 ms and then call itself again, repeatedly.
See here for further details on the difference.
I added setTimeout to the roll function and called it at the end.
var init = 0.01
var start = init
var $odds = $("#oddsOverUnder")
var $button = $("#roll")
var $bet = $("#bet")
function roll() {
setTimeout(roll, 2000)
$bet.val(start)
$button.click()
setTimeout(function() {
var tr = document.querySelector("#myBetsTable tr:nth-child(2)")
var cls = tr.getAttribute('class')
if (cls === 'success'){
start = init
$bet.val(start)}
else{
start = start * 2
$bet.val(start)
$odds.click()}
$button.click();
setTimeout(function() {
$button.click();
},1000);
},1000);
}
roll()
The best would be to do soemething like this:
function roll() {
var time = Date.now();
//your stuff goes here
setInterval(roll, Math.max(2000 - (Date.now() - time)), 1);
}
This tries to optimize tge amount of time between calls, so if the function took 1.5 seconds, then it will fire after 0.5 seconds.
I've looked at many different solutions to this, none of which worked. I know it has something to do with setTimeout, but I don't know how to implement it properly.
function myfunction()
{
//the function
//wait for 1 second before it can be ran again
}
To clarify: I don't want to call the function at a regular interval, I want to be able to enforce a delay before the function can be called again.
var lastTime = 0;
function myFunction() {
var now = new Date().getTime(); // Time in milliseconds
if (now - lasttime < 1000) {
return;
} else {
lastTime = now;
}
// rest of function
}
You don't need to use setTimeout at all. The following is similar to other answers, but uses a closure to remember the last time the function ran rather than a global variable.
var myFunction = function() {
var lastTime = new Date();
return function() {
var now = new Date();
if ((now - lastTime) < 1000) return;
lastTime = now;
/* do stuff */
};
}());
I think the easiest solution would be to hold a boolean variable and reset it to true after a given delay.
fiddle
HTML
<button id="clickme">click me!</button>
JavaScript
var canGo = true,
delay = 1000; // one second
var myFunction = function () {
if (canGo) {
canGo = false;
// do whatever you want
alert("Hi!");
setTimeout(function () {
canGo = true;
}, delay)
} else {
alert("Can't go!");
}
}
$("#clickme").click(function(){
myFunction();
})
With this, you hold a boolean, canGo, and set it to true. If the function is run, it sets canGo to false and sets a setTimeout() for a time period of delay, in milliseconds. If you try to run the function again, it won't run and will, instead, alert("Can't go!"). This was just for demonstrative purposes; you don't need that part. After delay, canGo will be set to true, and you will be able to once more run the function.
var lastRan = 0;
var myFunction = function() {
var now = Date.now();
if(now-lastRan < 1000) {
return;
}
lastRan = now;
//rest of function
};
You may want to use throttle or debounce from underscore.js
http://underscorejs.org/#throttle
throttle_.throttle(function, wait, [options])
Creates and returns a
new, throttled version of the passed function, that, when invoked
repeatedly, will only actually call the original function at most once
per every wait milliseconds. Useful for rate-limiting events that
occur faster than you can keep up with.
By default, throttle will execute the function as soon as you call it
for the first time, and, if you call it again any number of times
during the wait period, as soon as that period is over. If you'd like
to disable the leading-edge call, pass {leading: false}, and if you'd
like to disable the execution on the trailing-edge, pass {trailing:
false}.
var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);
http://underscorejs.org/#debounce
debounce_.debounce(function, wait, [immediate])
Creates and returns a
new debounced version of the passed function which will postpone its
execution until after wait milliseconds have elapsed since the last
time it was invoked. Useful for implementing behavior that should only
happen after the input has stopped arriving. For example: rendering a
preview of a Markdown comment, recalculating a layout after the window
has stopped being resized, and so on.
Pass true for the immediate parameter to cause debounce to trigger the
function on the leading instead of the trailing edge of the wait
interval. Useful in circumstances like preventing accidental
double-clicks on a "submit" button from firing a second time.
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
If you just want to run your function again after a set time, you can use setTimeout and pass it the function to run and the delay period in milliseconds.
function myfunction() {
//the function
//run again in one second
setTimeout(myfunction, 1000);
}
Edited based on poster's comments:
var waiting = false;
var myfunction = function() {
if (!waiting) {
//Run some code
waiting = setTimeout(function() {
waiting = false;
}, 1000);
}
};
As part of a Javascript project I'm working on, there are some synchronous ajax calls (I guess that makes it "sjax", but I digress). I'm now writing a debugging panel which would allow me to test out the site with some artificially simulated network conditions by wrapping $.ajax. Simple things: faking a 500 response etc, and making the ajax calls take much longer.
For the asynchronous calls, it's simple. When the real response comes back, add a setTimeout to make it wait for the artificial response time before triggering the callback. However, this doesn't work with the synchronous calls obviously, since setTimeout isn't synchronous.
So, is there a way to make a Javascript program perform a blocking wait for a set amount of time?
The only thing I could think of would be something like this:
function wait(ms) {
var start = +(new Date());
while (new Date() - start < ms);
}
Is there a better solution?
(Also, please assume there's a good reason for the blocking ajax calls... :-\)
Do not do it on the JavaScript level. Get a proxy such as Fiddler and set up an AutoResponder to delay the call by a time period.
If it's just for debugging purposes to have an artificial delay:
alert('block me one more time');
There is no reasonable other approach to have a blocking code in ECMAscript. Since Javascript is executed in the same thread ("UI thread") which browsers use to render the DOM and to certain other things, the whole show was designed not to block anything.
Of course you can fake it by using a loop, but its a perversion of the show.
I figured this code might help
// execute code consecutively with delays (blocking/non-blocking internally)
function timed_functions()
{
this.myfuncs = [];
this.myfuncs_delays = []; // mirrors keys of myfuncs -- values stored are custom delays, or -1 for use default
this.myfuncs_count = 0; // increment by 1 whenever we add a function
this.myfuncs_prev = -1; // previous index in array
this.myfuncs_cur = 0; // current index in array
this.myfuncs_next = 0; // next index in array
this.delay_cur = 0; // current delay in ms
this.delay_default = 0; // default delay in ms
this.loop = false; // will this object continue to execute when at end of myfuncs array?
this.finished = false; // are we there yet?
this.blocking = true; // wait till code completes before firing timer?
this.destroy = false; // <advanced> destroy self when finished
// handle next cycle execution
this.next_cycle = function() {
var that = this;
var mytimer = this.delay_default;
if(this.myfuncs_cur > -1)
if(this.myfuncs_delays[this.myfuncs_cur] > -1)
mytimer = this.myfuncs_delays[this.myfuncs_cur];
console.log("fnc:" + this.myfuncs_cur);
console.log("timer:" + mytimer);
console.log("custom delay:" + this.myfuncs_delays[this.myfuncs_cur]);
setTimeout(function() {
// times up! next cycle...
that.cycle();
}, mytimer);
}
this.cycle = function() {
// now check how far we are along our queue.. is this the last function?
if(this.myfuncs_next + 1 > this.myfuncs_count)
{
if(this.loop)
{
console.log('looping..');
this.myfuncs_next = 0;
}
else
this.finished = true;
}
// first check if object isn't finished
if(this.finished)
return false;
// HANDLE NON BLOCKING //
if(this.blocking != true) // blocking disabled
{
console.log("NOT BLOCKING");
this.next_cycle();
}
// set prev = current, and current to next, and next to new next
this.myfuncs_prev = this.myfuncs_cur;
this.myfuncs_cur = this.myfuncs_next;
this.myfuncs_next++;
// execute current slot
this.myfuncs[this.myfuncs_cur]();
// HANDLE BLOCKING
if(this.blocking == true) // blocking enabled
{
console.log("BLOCKING");
this.next_cycle();
}
return true;
}; // END :: this.cycle
// adders
this.add = {
that:this,
fnc: function(aFunction) {
// add to the function array
var cur_key = this.that.myfuncs_count++;
this.that.myfuncs[cur_key] = aFunction;
// add to the delay reference array
this.that.myfuncs_delays[cur_key] = -1;
}
}; // end::this.add
// setters
this.set = {
that:this,
delay: function(ms) {
var cur_key = this.that.myfuncs_count - 1;
// this will handle the custom delay array this.that.myfunc_delays
// add a custom delay to your function container
console.log("setting custom delay. key: "+ cur_key + " msecs: " + ms);
if(cur_key > -1)
{
this.that.myfuncs_delays[cur_key] = ms;
}
// so now we create an entry on the delay variable
}, // end :: this.set.delay(ms)
delay_cur: function(ms) { this.that.delay_cur = ms; },
delay_default: function(ms) { this.that.delay_default = ms; },
loop_on: function() { this.that.loop = true; },
loop_off: function() { this.that.loop = false; },
blocking_on: function() { this.that.blocking = true; },
blocking_off: function() { this.that.blocking = false; },
finished: function(aBool) { this.that.finished = true; }
}; // end::this.set
// getters
this.get = {
that:this,
delay_default: function() { return this.that.delay_default; },
delay_cur: function() { return this.that.delay_cur; }
}; // end::this.get
} // end ::: timed_functions()
And Test...
// // // BEGIN :: TEST // // //
// initialize
var fncTimer = new timed_functions;
// set some defaults
fncTimer.set.delay_default(1000); // set a default delay between function blocks
fncTimer.set.blocking_on(); // next timer begins count before code is executed
fncTimer.set.blocking_off(); // next timer begins count after code is executed
// fncTimer.set.loop_on(); // when finished start over
// fncTimer.set.loop_off();
// BEGIN :: ADD FUNCTIONS (they will fire off in order)
fncTimer.add.fnc(function() {
console.log('plan a (2 secs)');
});
fncTimer.set.delay(2000); // set custom delay for previously added function
fncTimer.add.fnc(function() {
console.log('hello world (delay 3 seconds)');
});
fncTimer.set.delay(3000);
fncTimer.add.fnc(function() {
console.log('wait 4 seconds...');
});
fncTimer.set.delay(4000);
// END :: ADD FUNCTIONS
// NOW RUN
fncTimer.cycle(); // begin execution
// // // END :: TEST // // //
The window.setTimeout (and related setInterval) function in Javascript allows you to schedule a function to be executed sometime in the future:
id = setTimeout(function, delay);
where "delay" is the number of milliseconds into the future at which you want to have the function called. Before this time elapses, you can cancel the timer using:
clearTimeout(id);
What I want is to update the timer. I want to be able to advance or retard a timer so that the function gets called x milliseconds sooner or later than originally scheduled.
If there were a getTimeout method, you could do something like:
originally_scheduled_time = getTimeout(id);
updateTimeout(id, originally_schedule_time + new_delay); // change the time
but as far as I can tell there's nothing like getTimeout or any way to update an existing timer.
Is there a way to access the list of scheduled alarms and modify them?
Is there a better approach?
thanks!
If you really want this sort of functionality, you're going to need to write it yourself.
You could create a wrapper for the setTimeout call, that will return an object you can use to "postpone" the timer:
function setAdvancedTimer(f, delay) {
var obj = {
firetime: delay + (+new Date()), // the extra + turns the date into an int
called: false,
canceled: false,
callback: f
};
// this function will set obj.called, and then call the function whenever
// the timeout eventually fires.
var callfunc = function() { obj.called = true; f(); };
// calling .extend(1000) will add 1000ms to the time and reset the timeout.
// also, calling .extend(-1000) will remove 1000ms, setting timer to 0ms if needed
obj.extend = function(ms) {
// break early if it already fired
if (obj.called || obj.canceled) return false;
// clear old timer, calculate new timer
clearTimeout(obj.timeout);
obj.firetime += ms;
var newDelay = obj.firetime - new Date(); // figure out new ms
if (newDelay < 0) newDelay = 0;
obj.timeout = setTimeout(callfunc, newDelay);
return obj;
};
// Cancel the timer...
obj.cancel = function() {
obj.canceled = true;
clearTimeout(obj.timeout);
};
// call the initial timer...
obj.timeout = setTimeout(callfunc, delay);
// return our object with the helper functions....
return obj;
}
var d = +new Date();
var timer = setAdvancedTimer(function() { alert('test'+ (+new Date() - d)); }, 1000);
timer.extend(1000);
// should alert about 2000ms later
I believe not. A better approach might be to write your own wrapper which stores your timers (func-ref, delay, and timestamp). That way you can pretend to update a timer by clearing it and calculate a copy with an updated delay.
Another wrapper:
function SpecialTimeout(fn, ms) {
this.ms = ms;
this.fn = fn;
this.timer = null;
this.init();
}
SpecialTimeout.prototype.init = function() {
this.cancel();
this.timer = setTimeout(this.fn, this.ms);
return this;
};
SpecialTimeout.prototype.change = function(ms) {
this.ms += ms;
this.init();
return this;
};
SpecialTimeout.prototype.cancel = function() {
if ( this.timer !== null ) {
clearTimeout(this.timer);
this.timer = null;
}
return this;
};
Usage:
var myTimer = new SpecialTimeout(function(){/*...*/}, 10000);
myTimer.change(-5000); // Retard by five seconds
myTimer.change(5000); // Extend by five seconds
myTimer.cancel(); // Cancel
myTimer.init(); // Restart
myTimer.change(1000).init(); // Chain!
It may be not exactly what you want, but take a look anyway, maybe you can use it to your benefit.
There is a great solution written by my ex-coworker that can create special handler functions that can stop and start timeouts when required. It is most widely used when you need to create a small delay for hover events. Like when you want to hide a mouseover menu not exactly at the time when a mouse leaves it, but a few milliseconds later. But if a mouse comes back, you need to cancel the timeout.
The solution is a function called getDelayedHandlers. For example you have a function that shows and hides a menu
function handleMenu(show) {
if (show) {
// This part shows the menu
} else {
// This part hides the menu
}
}
You can then create delayed handlers for it by doing so:
var handlers = handleMenu.getDelayedHandlers({
in: 200, // 'in' timeout
out: 300, // 'out' timeout
});
handlers becomes an object that contains two handler functions that when being called cancel the other one's timeout.
var element = $('menu_element');
element.observe('mouseover', handlers.over);
element.observe('mouseout', handlers.out);
P.S. For this solution to work you need to extend the Function object with the curry function, which is automatically done in Prototype.
One possibility can be like this:
if (this condition true)
{
setTimeout(function, 5000);
}
elseif (this condition true)
{
setTimeout(function, 10000);
}
else
{
setTimeout(function, 1000);
}
It's up to your how you construct your conditions or the logic. thanks
I use the following code to create countdowns in Javascript. n is the number of times to repeat, freq is the number of milliseconds to wait before executing, funN is a function to call on each iteration (typically a function that updates part of the DOM) and funDone is the function to call when the countdown is complete.
function timer(n, freq, funN, funDone)
{
if(n == 0){
funDone();
}else{
setTimeout(function(){funN(n-1); timer(n-1, freq, funN, funDone);}, freq);
}
}
It can be called like so:
timer(10,
1000, /* 1 second */
function(n){console.log("(A) Counting: "+n);},
function() {console.log("(A) Done!");}
);
timer(10,
500,
function(n){console.log("(B) Counting: "+n);},
function() {console.log("(B) Done!");}
);
The advantage of this is that I can call timer() as many times as I want without worrying about global variables etc. Is there a better way to do this? Is there a clean way to make setInterval stop after a certain number of calls (without using global variables)? This code also creates a new lambda function with each call to setTimeout which seems like it could be problematic for large countdowns (I'm not sure how javascript's garbage collector handles this).
Is there a better way to do this? Thanks.
This is basically the same idea as #balabaster, but it is tested, uses prototype, and has a little more flexible interface.
var CountDownTimer = function(callback,n,interval) {
this.initialize(callback,n,interval);
}
CountDownTimer.prototype = {
_times : 0,
_interval: 1000,
_callback: null,
constructor: CountDownTimer,
initialize: function(callback,n,interval) {
this._callback = callback;
this.setTimes(n);
this.setInterval(interval);
},
setTimes: function(n) {
if (n)
this._times = n
else
this._times = 0;
},
setInterval: function(interval) {
if (interval)
this._interval = interval
else
this._interval = 1000;
},
start: function() {
this._handleExpiration(this,this._times);
},
_handleExpiration: function(timer,counter) {
if (counter > 0) {
if (timer._callback) timer._callback(counter);
setTimeout( function() {
timer._handleExpiration(timer,counter-1);
},
timer._interval
);
}
}
};
var timer = new CountDownTimer(function(i) { alert(i); },10);
...
<input type='button' value='Start Timer' onclick='timer.start();' />
I'd create an object that receives a counter and receives a function pointer to execute, something akin to the following pseudo code:
TimedIteration = function(interval, iterations, methodToRun, completedMethod){
var counter = iterations;
var timerElapsed = methodToRun; //Link to timedMethod() method
var completed = callbackMethod;
onTimerElapsed = function(){
if (timerElapsed != null)
timerElapsed();
}
onComplete = function(){
if (completed != null)
completed();
}
timedMethod = function(){
if (counter != null)
if (counter > 0) {
setTimeOut(interval, onTimerElapsed);
counter--;
}
else
onComplete();
this = null;
}
}
if ((counter != null)&&(counter > 0)){
//Trip the initial iteration...
setTimeOut(interval, timedMethod);
counter--;
}
}
obviously this is pseudo code, I've not tested it in an IDE and syntactically I'm not sure if it'll work as is [I'd be astonished if it does], but basically what you're doing is you're creating a wrapper object that receives a time interval, a number of iterations and a method to run upon the timer elapsed.
You'd then call this on your method to run like so:
function myMethod(){
doSomething();
}
function doWhenComplete(){
doSomethingElse();
}
new TimedIteration(1000, 10, myMethod, doWhenComplete);
I like your original solution better than the proposed alternatives, so I just changed it to not create a new function for every iteration (and the argument of fun() is now the value before decrement - change if needed...)
function timer(n, delay, fun, callback) {
setTimeout(
function() {
fun(n);
if(n-- > 0) setTimeout(arguments.callee, delay);
else if(callback) callback();
},
delay);
}