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.
Related
I'm a JavaScript newbie and I'm trying to achieve concurrent actions with setInterval and setTimeout.
What I'd like to achieve, what actually happens and what I expected to happen is best explained with the following code.
var myVar = setInterval(function() {
myTimer()
}, 1000);
function myTimer() {
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("demo").innerHTML = t;
}
for (var i = 0; i < 100; i++) {
setTimeout(function() {
console.log("log " + i);
}, 3000);
}
<p>A script on this page starts this clock:</p>
<p id="demo"></p>
My expectation for the leading setInterval, is that the function myTimer is executed every second, independent of what happens afterwards. Except of course if the site is closed or clearTimeout is called on the myVar.
I can not verify if this action really happens independently and in an ongoing manner.
The following for loop, is there to simulate further code, to see if the myTimer function would be executed independently.
I expected the loop to start with i=0, then wait for three seconds, log log 0 to the console, then continue with i=1 and so on.
Instead it appears that the timeout is started and in the meantime i has reached the end of the for loop and is therefore 100.
How do I get the for loop to wait with the iteration for the setTimeout?
And is the setInterval really executed every second, independent of the following code? E.g. if the following code had actions that take some processing/time, would the clock update anyways, during the processing?
You could change the timeout time with the factor of i and use a closure over i to get the right value.
function myTimer() {
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("demo").innerHTML = t;
}
var i,
myVar = setInterval(myTimer, 1000);
for (i = 0; i < 100; i++) {
setTimeout(function (i) {
return function() {
console.log("log " + i);
};
}(i), 3000 * i);
}
<p>A script on this page starts this clock:</p>
<p id="demo"></p>
A version with calling timeout after timeout.
function myTimer() {
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("demo").innerHTML = t;
}
function next() {
i++;
console.log("log " + i);
if (i < 300) {
setTimeout(next, 3000);
}
}
var i = 0,
myVar = setInterval(myTimer, 1000);
setTimeout(next, 3000);
<p>A script on this page starts this clock:</p>
<p id="demo"></p>
About your setInterval question, yes. It will run every second (not being millisecond scrupulous). let's say you just set your setInterval, and then run an action that takes half a second to run. The interval will count that half second and run after another half second. Hard code will not delay the clock, BUT, if you are running code just in the moment that the interval should fire, it will wait for that code to end, as JavaScript is single threaded. This means that if right after setting your interval you run code that lasts more than 1 second, the interval callback will be ran after it, so it will not be fired in 1 second. By the way, subsequent interval calls will be called not after this interval, but after the interval was set. Check this fiddle (F12): https://jsfiddle.net/0gggmemu/4/
You see that the first interval is called when the code ends, but subsequent intervals are called counting when the interval was set (check milliseconds, how they fit the first log instead of the start one). Note that the intervals are not stacked. If it should have called 10 intervals, it will only call one and wait for the next. If time precision is important for you, then you should save a reference at startup and check the difference in each interval.
About concurrency, the same as when you call setInterval, when you call setTimeout the code will continue its execution, creating a hundred of timeouts at the same time. If you want code to hang just check my fiddle. By the way, if your worry is about setTimeout locking setInterval, don't worry, as the code will not be blocked. You only have to semi-worry if you have code that gets stuck somewhere, but in a callback-driven application is kinda difficult to achieve this.
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.
If I use the setInterval function to call an asynchronous JavaScript function each X seconds will the interval wait X seconds after the previous execution is finished or X seconds after the previous execution is called? E.g. if I display a timeline of the calls is it:
0 sec : setInterval(funcX, 10000)
10 sec : funcX - takes 3 seconds to execute
20 sec : funcX
or
0 sec : setInterval(funcX, 10000)
10 sec : funcX - takes 3 seconds to execute
23 sec : funcX
Taken from Mozilla documentation:
Calls a function or executes a code snippet repeatedly, with a fixed
time delay between each call to that function.
Therefore it's every X seconds. But if the function takes longer than X seconds to execute, then the thread will be locked and will execute when it's free.
For more information on JavaScript timings I recommend John Resig's article How JavaScript Timers Work.
If you wish for it to be X seconds after the function has executed, use setTimeout() and call this at the end of your function:
runFunc();
function runFunc(){
//code here....
setTimeout(runFunc, 3000);
}
This will cause infinite recursion, emulating setInterval(), but only starting the X second delay once the current function has finished executing.
If the function actually takes 3 seconds to execute, you have serious problems.
This is not particularly relevant to you because you are using Ajax, and the actual Ajax call should be practically instantaneous.
If you want the Ajax call to complete before the interval continues again, setInterval is undesirable. Use setTimeout instead.
function atTime() {
ajax().done(function () { setTimeout(atTime, 10000); });
}
atTime();
I need to be able to call this function to reset the interval.
I know this has been asked before. But the answer given at
Javascript - Reset setInterval back to 0
is not working for me.
Here is the code that I tried:
function startTimer(){
clearInterval(interval);
var interval = setInterval(function(){
advanceSlide();
}, 5000);
};
I call that at the beginning of my page to start a slideshow that changes every 5 seconds. and I use this code to call it again, witch I expected would reset that 5 seconds.
onclick=startTimer();>
The onclick does one other thing too, but this is what is not working. The other action takes place but the interval does not change, its still going based off the same portion of 5 seconds that was left before I clicked.
You need to declare the variable outside the function...
var interval;
function startTimer() {
clearInterval(interval);
interval = setInterval(advanceSlide, 5000);
}
Otherwise it is lost when the function exits.
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.