The second parameter in the setInterval function is for delaying the executing in milliseconds. and as expected 1000 millisecond will trigger the function every second. but here's a strange thing that I don't really understant. In the second interval, I've set the delay parameter to 1 millisecond and put inside the function incremental number and condition to check for every passed 1000 number.. I was expecting it to behave just like the seconds interval timer. but It doesn't quite run as I hoped.
Is there any explanation for that?
// detect seconds in a second interval timer (works as expected)
setInterval(function() {
console.log('passed second from the secondInterval');
}, 1e3);
// detect seconds in a millisecond interval timer (I don't have any explanation for the behavior).
(function() {
var i = 0;
setInterval(function() {
if (i === 0) {
i++;
return;
}
if (i % 1000 === 0) console.log('passed second from the millisecondInterval');
i++;
}, 1);
})();
check out the example in jsfiddle to see what I mean
http://jsfiddle.net/dwh82zos/
This happens. The sentence is not logged every second, or whatever your machine can. You are running out of memory, can't resolve, first time 6 operations per 1ms and second 3 operations per 1ms.
Take a look of this What is minimum millisecond value of setTimeout? it is about setTimeout but it useful.
Related
I am making a timer in javascript. But there is one thing I am not getting.
Here's the code...
var time = 0;
var timeInterval;
var testTime;
//Main code which increases the value of variable time by 1 every second until interval is stopped
timeInterval = setInterval(function (){
time++;
testTime = time;
}, 1000);
//Code to stop the interval after 10 seconds.
setTimeOut(function() {
clearInterval(timeInterval);
},10000);
//Expected value -> 10
//I get -> 0
console.log(testTime)
If I am running a function which increases the value of time by 1 10times by setInterval() method... Why the value of time is not updating?
When you call setInterval, you are asking code to run after a certain amount of time. The setInterval function is an example of a function that takes a function as a parameter.
This means that you're declaring a function and asking setInterval to call it at a later time all in one go. None of what is inside the function will be called until the interval happens.
Your console.log is not inside either of the functions you gave to setInterval or setTimeout, so it will run straight away.
The order of execution is:
Your variables are declared
Your call to ask setInterval to run your function periodically
Your call to ask setTimeout to run your function after 10 seconds
Your console.log is made
At this point, the execution on your main thread ends
The function you gave to setInterval is called a bunch of times
The function you gave to setTimeout is called once
If you want to fix your code, you can put the console.log in the setTimeout function to ask it to run at the end of the 10 seconds (putting it inside step 7).
var time = 0;
// Main code which increases the value of variable time by 1 every second until interval is stopped
var timeInterval = setInterval(function (){
time++;
console.log("time during interval: ", time);
}, 1000);
// Code to stop the interval after 10 seconds.
setTimeout(function() {
clearInterval(timeInterval);
console.log("time at end: ", time);
}, 10000);
Depending on your objective, you might rather simplify your code by calling clearInterval inside your interval function (if(time > 10) clearInterval(...)) to reduce the likelihood of a bug.
My fiddle link is as follows:http://jsfiddle.net/FvYyS/2/
The function call is as follows:
load_timer('0', '6', '9', 0, '0', '', '0');
Actually my issue is the fiddle is not working. The expected behaviour of this code is the timer should decrease second by second and ultimately reaches to zero(i.e. for example the timer should start at 00:06:09 and end at 00:00:00). But it's not working here in the fiddle. The code is working properly in my application but don't know why this code is not working in fiddle. Also one more issue I noticed in my application is the timer is lagging sometime behind. Can anyone please help me in this regard? If you need any further information I'll provide you the same. Thanks in advance.
Your code has the following structure :
var counter = delay;
function loop() {
counter--;
displayTime(delay, counter);
if (counter > 0) {
setTimeout( loop, 1000 );
}
}
2 things :
displayTime() execution takes time : for example, if it takes 0.2 seconds to complete, the loop will be executed every 1.2 seconds (instead of every second)
setTimeout( ..., 1000 ) means "Please dear javascript runtime, can you run my code in 1 second ? If you have other stuff to do, it is ok for me to wait more."
You have the guarantee that there will be at least 1 second between the setTimeout call and your loop excution, but the delay can be longer.
If you want to avoid the time drift, check for the real time on each iteration :
var start = Date.now();
function loop() {
var now = Date.now();
var elapsedTime = now - start; //elapsed time in milliseconds
displayTime(delay, elapsedTime);
if (elapsedTime < delay) {
setTimeout(loop, 1000);
}
}
you have not included the jquery library in your fiddle
See UPDATED FIDDLE
There are several problems with your approach:
Since you do the setTimeout after doing some work, the time it takes for your work to be done will delay the next iterations. You could fix this by moving the setTimeout call to be the first executed and then do the work.
Using setTimeout(f, timeout) guarantees that the f function will be executed at least timeout miliseconds after the setTimeout call. So if for example the browser is busy for 1 second when the call to f should be executed, the call to f is delayed by 1 second. Furthermore, the next call to setTimeout is delayed by that second, so everything coming after that will incur your delay.
A better fix would be to use setInterval which is designed with repeating a task every n miliseconds and alleviates the recurrent delay problem.
Finally, the best solution to the problem is to use Date to determine the start of your counter and show the exact time elapsed by substracting the original time from the current time.
The code I wrote to call a function on the minute every minute, I think is flawed, as It's good for a while, but tends to lag behind by about 15 seconds for every hour since the page was loaded. To be honest I can't figure out what's causing the lagging, maybe it's the time it takes the functions to execute, small lapses all adding up and accumulating. Is there a way to auto-correct the lapses within the function as it's called. Or maybe someone knows a better method of achieving on the minute function calls. Any help or ideas much appreciated. Thanks.
var now = new Date();
var delay = 60 * 1000; // 1 min in msec
var start = delay - (now.getSeconds()) * 1000 + now.getMilliseconds();
setTimeout(function setTimer() {
onTheMinFunc();
setTimeout(setTimer, delay);
}, start);
First of all, the DOM Timers API does not guarantee accuracy. I quote:
This API does not guarantee that timers will run exactly on schedule. Delays due to CPU load, other tasks, etc, are to be expected.
Second, you have a lag on each round caused by the time onTheMinFunc() is executed (you only set the timeout when it's done).
So, let's say onTheMinFunc takes half a second to execute - you get half a second delay at each minute and it accumulates - after only 10 minutes it'll lag quite a bit. (Note, functions should usually not take more than 15ms to execute anyway to avoid noticeable lag)
Try:
setInterval(onTheMinFunc, delay);
It still won't be very accurate. You can poll on much shorter intervals and keep track of a date variable - but again - no guarantees.
What you probably want is setInterval:
setInterval(onTheMinFunc, delay);
As is, your code using setTimeout means that the time it takes to execute your onTheMinFunc is being added into your delay before the next one is started, so over time, this extra delay will add up.
Using setInterval will be more accurate, since the delay is between calls to execute the function, rather than starting the timer only after the function is finished.
Timers and javascript times aren't very accurate, and I would think the only way to make sure a function is executed every whole minute over time, is to check the seconds every second
setInterval(function() {
if ( new Date().getSeconds() === 0 ) onTheMinFunc();
},1000);
FIDDLE
Here is a slight modification to your code:
function everyMinute(fn) {
arguments[1] && fn();
var now = new Date();
var delay = 60 * 1000 - (now.getSeconds()) * 1000 + now.getMilliseconds();
setTimeout(function(){
everyMinute(fn, true);
}, start);
}
everyMinute(onTheMinFunc);
It recalculates the number of milliseconds to wait till the next minute every time so it is as accurate as possible to the top of the minute.
I think you want something closer to this:
function setNextMinute() {
// figure out how much time remains before the end of the current minute
var d = new Date().getTime()%60000;
//set a timeout to occur when that expires.
setTimeout(function () {
// recalculate a new timeout so that your timer doesn't lag over time.
doWhateverYouWantToHere();
// note that calling doWhateverYouWantToHere() will
// not offset the next minute, since it is recalculated in setNextMinute()
setNextMinute();
},60000-d);
}
setNextMinute();
caveat: I did not thoroughly test this for timing. But it appeared to work for 1 sec intervals and 1 min intervals well enough.
This has the advantage of not recalculating every second, and also not just starting a 60 second timer from whatever the current time is.
The current accepted answer may overkill
Executing if ( new Date().getSeconds() === 0 ) onTheMinFunc(); on each second (and forever) seems to not be a good idea.
I will not benchmark it against the following propositions, it's not necessary.
Clues
Use whatever logic is necessary to calculate the start moment.
On the start moment
Use setInterval for remaning executions
Execute the first call
Note setInterval is called ASAP to avoid that time lapses.
If you want that new Date().getSeconds() === 0:
var id = setInterval(function() {
if ( new Date().getSeconds() === 0 ) {
setInterval(onTheMinFunc, delay);
onTheMinFunc();
clearInterval(id);
}
},1000);
Alternatively, you could use your own logic:
var now = new Date();
var delay = 60 * 1000; // 1 min in msec
var start = delay - (now.getSeconds()) * 1000 + now.getMilliseconds();
setTimeout(function() {
setInterval(onTheMinFunc, delay);
onTheMinFunc();
}, start);
Please check both examples working on jsfiddle
The second (Example B) seems more accurate.
I'm trying to make a countdown that is counting down in milliseconds; however, the countdown actually takes much longer than 7 seconds. Any idea as to why?
function countDown(time){
var i = 0;
var interval = setInterval(function(){
i++;
if(i > time){
clearInterval(interval);
}else{
//mining
$('#mining_time').text($('#mining_time').text()-1);
}
}, 1);
}
And I can confirm the varible time passed to the function is correctly set to 7000.
For a mostly-accurate countdown, use setTimeout().
setTimeout(fn, 7e3);
If you absolutely must have it as close to 7 seconds as possible, use a tight poll (requestAnimationFrame()) and look at difference between the time of start and current poll.
var startTime = Date.now();
requestAnimationFrame(function me() {
var deltaTime = Date.now() - startTime;
if (deltaTime >= 7e3) {
fn();
} else {
requestAnimationFrame(me);
}
});
Poly-fill as required.
the most precise way to run something after 7 seconds - is to use setTimeout with 7000 ms interval
a. there is no browser that guarantees an interval to run with 1ms resolution. In the best case it would be 7-10ms
b. there is only one thread in js, so the tasks are queued. It means that the next run will be scheduled to only after the current run is finished.
Some useful reading: http://ejohn.org/blog/how-javascript-timers-work/
No browser will take 1 as parameter for setInterval. Off the top of my head the minimum is 4 ms.
For an accurate result, get the current time, add 7000 ms, and poll (using setInterval or setTimeout) until you reach that new time.
A quick Web search returned this article that provides an example.
[Update] the value of 4 ms is mentioned on this MDN page.
base ={time:0};
var loop = 0;
setInterval(function(){
if(base.time === 9000){
move();
base.time = 0;
}
base.time ++;
},1);
Shouldn't the move(); function occur every 9s? I timed it and its much less, why is that?
setInterval will not run every millisecond. There is a minimum possible interval that is longer than that.
If you want something to run in nine seconds, you should use setTimeout() for 9 seconds. Plus your code doesn't reset base.time back to zero so it would only match 9000 once anyway.
If you want it to run every 9 seconds, then you can use setInterval(handler, 9000) or you can use setTimeout(handler, 9000) and then set the next setTimeout in your handler function.
This will execute move() every nine seconds:
var intervalTimer = setInterval(function(){
move();
}, 9000);
Here's a useful article on the topic: http://www.adequatelygood.com/2010/2/Minimum-Timer-Intervals-in-JavaScript.
To reset the time back to 9 seconds when a button is clicked use this code:
var intervalTimer;
function startTimer() {
intervalTimer = setInterval(function(){
move();
}, 9000);
}
function handleClick() {
clearInterval(intervalTimer); // stop currently running interval
startTimer();
}
startTimer();
See it in action here: http://jsfiddle.net/jfriend00/sF2by/.
Intervals are easy as pie!
var move = function(){
alert("move!");
};
setInterval(move, 9000);
See it work here on jsFiddle
You can't count on setInterval actually running every 1 ms. If the CPU is used for another process, it might not run for 1 second. Instead, use one of the following:
function move() {
// Do stuff.
}
// The obvious solution.
// Certain browsers (Chrome) may put the script in "inactive" mode which will
// pause setInterval code. This means move will be run too few times, if you
// actually depend on it being called X times for Y time.
setInterval(move, 9000);
// The other solution.
// Get the delta between each loop and run the move loop as necessary.
// WARNING: This is not efficient, and you should only use this if you have a
// good reason to do so.
// EXTRA WARNING: This code is actually retarded in its current form. It's just
// here to show you how you'd do it. Since you didn't post your
// original problem, it's hard to know what you're really after.
var time = +new Date, frequency = 9000;
setInterval(function () {
var dt = new Date - time;
// Check if we've waited long enough.
if (dt >= frequency) {
// If the process hangs for 20 seconds, this value would be 2. Usually,
// it will be 1.
// Also, Chrome will pause interval counters, so if a tab is inactive,
// this count could be really high when the tab gets focus again.
var times = Math.floor(dt / frequency);
console.log('Moving', times, 'time(s)!');
for (var i = 0; i < times; i++) {
move();
}
// Start counting time from the last update.
time += times * frequency;
}
}, 1); // 1 could probably be much higher here. Depends on your use case.
You wrote in a comment that there is a button which resets the time, and that's why you don't want to just setTimeout for the full delay. Here's how to handle that:
var running;
function start() {
clearInterval(running);
running = clearInterval(function () {
move();
}, 9000);
}
Every time start() is called, the time will be reset to 9 seconds from now, and if 9 seconds elapse, move() will be called and another 9-second interval will start. If you don't actually want it to happen repeatedly, just use setTimeout instead.
The key is using clearInterval (or clearTimeout) to cancel your previous 9-second-delay and start a new one. It is harmless to call clearInterval with a junk value.