Concurrent actions with setInterval and setTimeout - javascript

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.

Related

function executed by setInterval() multiple doesn't show results | Javascript

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.

Why the fiddle is not working and there is a time lag behind in following case?

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.

SetInterval inside a Closure, inside a For loop, creates too many intervals, won't stop running

I've got some rather complicated logic:
var myArray = [];
var tempInterval = 0;
// Run for 6 minutes
for(i=0;i<360;i++) {
// Closure so that 'i' is the right value when setInterval runs
tempInterval = (function(i) {
interval1 = setInterval(function() {
console.log(i);
}, (i * 1000));
return interval1;
})(i);
// Put the setInterval value into an array
myArray.push(tempInterval);
}
I use a Closure because I need the value of i to be 0,1,2,...etc, and if you don't use a closure, it'll be 360 by the time the interval executes.
If you run that in your console, you'll see it runs way more than 360 times. For some reason, it's creating too many intervals.
I want to have a function to stop this execution of setIntervals:
for(i=0; i<myArray.length; i++) {
clearInterval(myArray[i]);
}
But, because it creates too many, I can't get it to stop.
For example, if you run it inside for(i=0; i<5; i++) instead of for(i=0;i<360;i++), you'll see, it still runs indefinitely.
Why is it creating so many intervals, and how do I get it to run only 360 times? Also, is that the right way to save the intervals, so I can use clearInterval to stop their execution?
The problem
setInterval does not mean "sleep", it means "Run this function every time period".
Each of the 360 times you go around the loop, you call setInterval saying "Run this function every i seconds.
So you get 360 countdowns, each of which runs a function when it hits zero before restarting the countdown to run the function again.
The solution
Don't use setInterval. Use setTimeout.
Or, alternatively:
I'd generally avoid setting 360 timers running at once and instead do something like:
var i = 0;
function next() {
console.log(i);
i++;
if (i < 360) {
setTimeout(next, 1000);
}
}
next();

for loop delay in javascript

How to set delay in for loop execution
for(i=0; i<=10;i++){
var s=i;//This line should execute for every 2 secs only
}
How to give loop delay in java script....
I dont want like below..I want without using setTimeout...
for(i=0; i<=10;i++){
setTimeout("setvalue()",2000); //This alert should display for every 2 secs only
}
function setvalue()
{
var s=i;
}
please help me...
Use setInterval()
var i = 0;
var interval = setInterval(function(){
setValue();
i += 1;
if(i == 10)
clearInterval(interval);
}, 2000);
There is no way to sleep for 2sec without freezing the whole browser. Javascript is single threaded.
You can't. JS runs in a single thread and any attempt to delay that thread will freeze the entire page. Using setTimeout is your only option.
EDIT: or setInterval; either way, there is no non-hairy way to express "halt execution here for x milliseconds."
Using setTimeout is inevitable, however, a recursive function might be a better solution for this one:
var i=0;
function recurs() {
i = s;
i++;
if (i <= 10) recurs();
}
recurs();
As others have stated, setTimeout can be used very well to handle these sorts of scenarios and setInterval could also be used but is discouraged by some.
You can even recursively call a function that has setTimeout built into it as mentioned in the MDN documentation of setInterval. The heading there mentions 'dangerous usage' but their solution to the danger is the block of code beneath.
There it mentions that to have a loop executing every x seconds (or milliseconds) then you can do the following and know for sure that the functions will only be executing one at a time and in-sequence:
(function loop(){
setTimeout(function(){
// logic here
// recurse
loop();
}, 1000); // repeat loop 1 second after this branch has completed
})();
And if you want it to only do that a limited number of times, then you can create a variable outside of the loop and only recursively execute if the count is smaller than the number of times you want to execute for. Such as this:
var count = 0;
(function loop() {
setTimeout(function() {
// logic
count++;
if (count < 10) {
loop();
}
}, 1000);
})();

Javascript SetInterval timing issue, total time

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.

Categories