problem running a setInterval () inside a while in javascript? [duplicate] - javascript

This question already has answers here:
What is the JavaScript version of sleep()?
(91 answers)
Closed 3 years ago.
I need to run a setInterva () but when trying to do it within a while cycle the setInterval() never runs. I'm a beginner in javascript so I don't know what the reason is.
The code I try to execute is the following:
var i = 0;
while(i < 5){
var c = 0;
var t = setInterval(function(){
c++;
if(c==5){
clearInterval(t);
}
},2000);
i++;
}
What is the method to create a time.sleep() within a while cycle in javascript?

As mentioned in the comments above, setInterval() does not pause code execution. Instead everything else runs as normal, but after the set amount of time it runs the function. Also, you want to use setTimeout because it only runs once. It looks like you just want to increment c by one every five seconds. Do so like this:
let i = 0;
let c = 0;
while (i < 5) {
setTimeout(() => c += 1, 5000/*number of milliseconds you want to wait*/ * (i + 1))
}
so, i will increment after 5000 milliseconds, 10000 milliseconds, 15000, etc.
Just so you know: () => i+= 1 is the same as
function() {
i += 1
}
With some refactoring, and using for loops, your code becomes:
let c = 0
for(let k = 0; k < 5; k += 1) setTimeout(() => c += 1, 5000 * (k + 1))

Related

How to Change Interval Time Dynamically in For Loop According to Index/iteration Number?

Since I could not comment, I am forced to write this post. I got the below code which delays/waits exactly 1 seconds or 1000 milliseconds -
let n = 5;
for (let i=1; i<n; i++)
{
setTimeout( function timer()
{
console.log("hello world");
}, i*1000 );
}
But how can I delay it i*1000 seconds instead of fixed 1000 milliseconds so the waiting depends on iteration number ?
For example, if n= 5 , then I want the loop delay 1 second in 1st iteration. 2 seconds in second iteration, and so on.. the final delay will 5 seconds.
While this task could be solved with promises, reactive streams and other cool tools (hey, nobody has suggested using workers yet!), it can also be solved with a little arithmetics.
So you want timeouts in a sequence: 1s, the previous one + 2s, the previous one + 3s, and so on. This sequence is: 1, 3, 6, 10, 15... and its formula is a[n] = n * (n + 1) / 2. Knowing that...
let n = 6;
console.log(new Date().getSeconds());
for (let i = 1; i < n; i++) {
setTimeout(function timer() {
console.log(new Date().getSeconds());
}, 1000 * i * (i + 1) / 2);
}
Here is a function that will show immediately, then 1 second later, 2 seconds after than, 3 seconds after that etc. No special math, no promises needed
const n = 5;
let cnt=0;
function show() {
console.log("call "+cnt,"delay: ",cnt,"sec");
cnt++;
if (cnt > n) return; // we are done
setTimeout(show, cnt*1000 ); // cnt seconds later
}
show()
You can try using async/await (Promises), to serialize your code:
const waitSeconds = seconds => new Promise(resolve => setTimeout(resolve, seconds))
async function main () {
let oldDate = new Date()
let newDate
/*
* If you put 'await' inside the loop you can synchronize the async code, and simulate
* a sleep function
*/
for (let i=1; i<5; i++) {
await waitSeconds(i*1000)
newDate = new Date()
console.log(`Loop for i=${i}, elapsed=${moment(newDate).diff(oldDate, 'seconds')} seconds`)
oldDate = newDate
}
console.log('End')
}
main()
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
Took me some time to decipher your question xD, but is this what you want?
This will keep firing console.log with i*1000 delay each time.
so the first time it will be 1 second long (1*1000), next it will be 2 seconds and so on.
let i = 0;
loop = () => {
setTimeout(() => {
console.log(new Date()); // for clarity
i++;
if (i < 10) {
loop();
}
}, i * 1000)
};
loop();
Loop doesn't waits for timeout function to be completed.
So, when the loop runs it schedules your alert for each index.
You can use a function which will run according to your index but scheduled at same time. You can feel the difference of 3 seconds.
function test(i){
setTimeout( function timer(){
console.log("hello world" + i);
}, i*3000);
}
for (let i=1; i<4; i++) {
test(i);
}
Use recursive calls instead of for loop
let i=1;
function a(i) {
if (i > 5)
return
else
b("message", i)
}
function b(s, f) {
setTimeout(function timer() {
console.log(s + " " + f + " seconds");
}, f * 1000);
a(++i);
}
a(i);

CSS Clip-Path Animation with Javascript

I try to animate the Clip-Path Property with JavaScript.
Means: It "grows" with help of SetTimeout.
I tried this, but it doesn't work.
http://jsfiddle.net/071dm2h3/8/
var el = document.getElementById("image")
function grow(i) {
el.style.clipPath = "circle("+ i +"px at 190px 160px)";
}
var i;
for(i = 0; i < 100; i++) {
setTimeout(grow(i), 400);
}
What am I missing here? Shouldn't the setTimeout change the value of I in every loop, so that I can see the result immediately?
To get this to work, I rewrote your setTimeout to be around your loop to make the image grow.
setTimeout( function(){
for(i = 0; i < 100; i++) {
grow(i)
}
},400);
Here is the jsfiddle
No, setTimeout fires once, and only once. Additionally, the way you are using setTimeout will lead to unintended results. You are basically saying:
I want to call grow(i) 400 milliseconds from now 100 times.
That means that 400 milliseconds from now, grow(i) will be called 100 times simultaneously. You don't want that, you want to call `grow(i) 100 times, waiting 400 milliseconds between each iteration.
Instead, you should either use setInterval which will wait a duration between each call or have each setTimeout schedule the next timeout after a duration.
Consider:
This will wait 2 seconds and then print 1,2,3,4 all at the same time.
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 2000);
}
This will print each iteration after a duration:
function iteration(i) {
console.log(i);
if (i > 3) return;
setTimeout(() => iteration(i + 1), 500);
}
iteration(0);
change you javascript to this
var el = document.getElementById("image")
function grow(i) {
console.log(i)
el.style.clipPath = "circle("+ i +"px at 190px 160px)";
}
var i;
for(i = 0; i < 100; i++) {
setTimeout( ((i) => () => grow(i))(i), i*10);
}
and kindly read this once
setTimeout in for-loop does not print consecutive values

How do I delay this code running in JavaScript?

I have written this code to change an image:
change = function(){
for (r=0; r<6; r++){
for (i = 0; i < 6 ; i++) {
setInterval(imgfile(number=i+1), 5000);
}
}
}
imgfile= function(number){
a = 'document.getElementById("imgdiv").src = "images/'+number+'.svg"';
eval(a);
}
The function change() is called when a button is clicked.
When I press the button the image changes straight to 6.svg, when I want it to go through the images 1, 2, 3, 4, 5, 6 and to repeat it 6 times. When I change setInterval to change.setInterval or imgfile.setInterval it doesn't work at all. How do I fix this?
change = function(i=0){
imgfile(i%6+1);//change image
if(i<36) setTimeout(change,5000,i+1);//next image in 5 seconds
}
imgfile= function(number){
document.getElementById("imgdiv").src = "images/"+number+".svg";//no need to use ev(i||a)l
}
Instead of loop/interval mess you can simply start a timeout that restarts itself after changing the image... This code will loop over 6 images with a delay of 5 seconds and that 6 times...
Something like this, perhaps?
var index, imgCount, loopCount, imgTag, countdown;
index = 0;
imgCount = 6;
loopCount = 6;
imgTag = document.getElementById('imgdiv');
countdown = function () {
if (index < imgCount * loopCount) {
imgTag.src = 'images/' + index % imgCount + '.svg';
index = index + 1;
setTimeout(countdown, 5000);
}
};
countdown();
Here we're avoiding the double loop and using modular math (index % imgCount) to get the right file number.
For another question I wrote a nice utility function that has quite a number of uses, but can also handle this scenario very easily. The main issue is that there is no time elapsing between the different delays being set. So you are setting 6 different actions to all happen within 5000ms, and all will occur at the same moment.
Here's my original answer
Here's the utility function for that answer, along with its application to your problem.
function doHeavyTask(params) {
var totalMillisAllotted = params.totalMillisAllotted;
var totalTasks = params.totalTasks;
var tasksPerTick = params.tasksPerTick;
var tasksCompleted = 0;
var totalTicks = Math.ceil(totalTasks / tasksPerTick);
var initialDelay = params.initialDelay;
var interval = null;
if (totalTicks === 0) return;
var doTick = function() {
var totalByEndOfTick = Math.min(tasksCompleted + tasksPerTick, totalTasks);
do {
params.task(tasksCompleted++);
} while(tasksCompleted < totalByEndOfTick);
if (tasksCompleted >= totalTasks) clearInterval(interval);
};
// Tick once immediately, and then as many times as needed using setInterval
if (!initialDelay) doTick();
if (tasksCompleted < totalTicks) interval = setInterval(doTick, totalMillisAllotted / totalTicks);
}
// Do 6 actions over the course of 5000 x 6 milliseconds
doHeavyTask({
totalMillisAllotted: 5000 * 6,
totalTasks: 6,
tasksPerTick: 1,
initialDelay: false, // Controls if the 1st tick should occur immediately
task: function(n) { console.log('Set image to "images/' + (n + 1) + '.svg"'); }
});
You want to do setTimeout().
setTimeout pauses for the millesecond value and then does the code. Where setInterval runs the code every whatever milleseconds.
Yeah, don't do change.setInterval or whatever, it is just setInterval.
An example for you would be this inside the for loop to replace the setInterval function.
setTimeout(imgfile(i+1), 5000);

How to create pause or delay in FOR loop?

I am working on a website, where I need to create a pause or delay.
So please tell me How to create pause or delay in for loop in javascript or jQuery
This is a test example
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
s.innerHTML = s.innerHTML + i.toString();
//create a pause of 2 seconds.
}
You can't use a delay in the function, because then the change that you do to the element would not show up until you exit the function.
Use the setTimeout to run pieces of code at a later time:
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
// create a closure to preserve the value of "i"
(function(i){
window.setTimeout(function(){
s.innerHTML = s.innerHTML + i.toString();
}, i * 2000);
}(i));
}
var wonderfulFunction = function(i) {
var s = document.getElementById("div1"); //you could pass this element as a parameter as well
i = i || 0;
if(i < 10) {
s.innerHTML = s.innerHTML + i.toString();
i++;
//create a pause of 2 seconds.
setTimeout(function() { wonderfulFunction(i) }, 2000);
}
}
//first call
wonderfulFunction(); //or wonderfulFunction(0);
You can't pause javascript code, the whole language is made to work with events, the solution I provided let's you execute the function with some delay, but the execution never stops.
I tried all one, but I think this code is better one, it is very simple code.
var s = document.getElementById("div1");
var i = 0;
setInterval(function () {s.innerHTML = s.innerHTML + i.toString(); i++;}, 2000);
if you want to create pause or delay in FOR loop,the only real method is
while (true) {
if( new Date()-startTime >= 2000) {
break;
}
}
the startTime is the time before you run the while
but this method will cause the browsers become very slow
It is impossible to directly pause a Javascript function within a for loop then later resume at that point.
This is how you should do it
var i = 0;
setTimeout(function() {
s.innerHTML = s.innerHTML + i.toString();
i++;
},2000);
The following code is an example of pseudo-multithreading that you can do in JS, it's roughly an example of how you can delay each iteration of a loop:
var counter = 0;
// A single iteration of your loop
// log the current value of counter as an example
// then wait before doing the next iteration
function printCounter() {
console.log(counter);
counter++;
if (counter < 10)
setTimeout(printCounter, 1000);
}
// Start the loop
printCounter();
While several of the other answers would work, I find the code to be less elegant. The Frame.js library was designed to solve this problem exactly. Using Frame you could do it like this:
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
Frame(2000, function(callback){ // each iteration would pause by 2 secs
s.innerHTML = s.innerHTML + i.toString();
callback();
});
}
Frame.start();
In this case, it is nearly the same as the examples that use setTimeout, but Frame offers a lot of advantages, especially if the you are trying to do multiple or nested timeouts, or have a larger JS application that the timeouts need to work within.
I am executing a function where I need access to the outside object properties. So, the closure in Guffa solution doesn't work for me. I found a variation of nicosantangelo solution by simply wrapping the setTimeout in an if statement so it doesn't run forever.
var i = 0;
function test(){
rootObj.arrayOfObj[i].someFunction();
i++;
if( i < rootObj.arrayOfObj.length ){
setTimeout(test, 50 ); //50ms delay
}
}
test();
The way I found was to simply use setInterval() to loop instead. Here's my code example :
var i = 0;
var inte = setInterval(() => {
doSomething();
if (i == 9) clearInterval(inte);
i++;
}, 1000);
function doSomething() {
console.log(i);
};
This loops from 0 to 9 waiting 1 second in between each iteration.
Output :
0 1 2 3 4 5 6 7 8 9
It is not possible to pause a loop. However you can delay the execution of code fragments with the setTimeout() function. It would not make a lot of sense to pause the entire execution anyway.
I am using while loop and check the pause variable to check the user pause/resume the code.
var pause = false;
(async () => {
for (let index = 0; index < 1000; index++) {
while (pause) {
await new Promise((res) => setTimeout(res, 1000));
console.log("waiting");
}
await new Promise((res) => setTimeout(res, 1000));
console.log(index);
}
})();
const pausefunc = async () => {
pause = true;
};
const playfunc = () => {
pause = false;
};
<button onclick="playfunc()">Play</button>
<button onclick="pausefunc()">Pause</button>
I used a do...while loop to put a delay in my code for a modal dialog that was closing too quickly.
your stuff....
var tNow = Date.now();
var dateDiff = 0;
do {
dateDiff = Date.now() - tNow;
} while (dateDiff < 1000); //milliseconds - 2000 = 2 seconds
your stuff....

Same code takes longer if executed more often?

I've got the following code inside a <script> tag on a webpage with nothing else on it. I'm afraid I do not presently have it online. As you can see, it adds up all primes under two million, in two different ways, and calculates how long it took on average. The variable howOften is used to do this a number of times so you can average it out. What puzzles me is, for howOften == 1, method 2 is faster, but for howOften == 10, method 1 is. The difference is significant and holds even if you hit F5 a couple of times.
My question is simply: how come?
(This post has been edited to incorporate alf's suggestion. But that made no difference! I'm very much puzzled now.)
(Edited again: with howOften at or over 1000, the times seem stable. Alf's answer seems correct.)
function methodOne(maxN) {
var sum, primes_inv, i, j;
sum = 0;
primes_inv = [];
for ( var i = 2; i < maxN; ++i ) {
if ( primes_inv[i] == undefined ) {
sum += i;
for ( var j = i; j < maxN; j += i ) {
primes_inv[j] = true;
}
}
}
return sum;
}
function methodTwo(maxN) {
var i, j, p, sum, ps, n;
n = ((maxN - 2) / 2);
sum = n * (n + 2);
ps = [];
for(i = 1; i <= n; i++) {
for(j = i; j <= n; j++) {
p = i + j + 2 * i * j;
if(p <= n) {
if(ps[p] == undefined) {
sum -= p * 2 + 1;
ps[p] = true;
}
}
else {
break;
}
}
}
return sum + 2;
}
// ---------- parameters
var howOften = 10;
var maxN = 10000;
console.log('iterations: ', howOften);
console.log('maxN: ', maxN);
// ---------- dry runs for warm-up
for( i = 0; i < 1000; i++ ) {
sum = methodOne(maxN);
sum = methodTwo(maxN);
}
// ---------- method one
var start = (new Date).getTime();
for( i = 0; i < howOften; i++ )
sum = methodOne(maxN);
var stop = (new Date).getTime();
console.log('methodOne: ', (stop - start) / howOften);
// ---------- method two
for( i = 0; i < howOften; i++ )
sum = methodTwo(maxN);
var stop2 = (new Date).getTime();
console.log('methodTwo: ', (stop2 - stop) / howOften);
Well, JS runtime is an optimized JIT compiler. Which means that for a while, your code is interpreted (tint), after that, it gets compiled (tjit), and finally you run a compiled code (trun).
Now what you calculate is most probably (tint+tjit+trun)/N. Given that the only part depending almost-linearly on N is trun, this comparison soes not make much sense, unfortunately.
So the answer is, I don't know. To have a proper answer,
Extract the code you are trying to profile into functions
Run warm-up cycles on these functions, and do not use timing from the warm-up cycles
Run much more than 1..10 times, both for warm-up and measurement
Try swapping the order in which you measure time for algorithms
Get into JS interpretator internals if you can and make sure you understand what happens: do you really measure what you think you do? Is JIT run during the warm-up cycles and not while you measure? Etc., etc.
Update: note also that for 1 cycle, you get run time less than the resolution of the system timer, which means the mistake is probably bigger than the actual values you compare.
methodTwo simply requires that the processor execute fewer calculations. In methodOne your initial for loop is executing maxN times. In methodTwo your initial for loop is executing (maxN -2)/2 times. So in the second method the processor is doing less than half the number of calculations that the first method is doing. This is compounded by the fact that each method contains a nested for loop. So big-O of methodOne is maxN^2. Whereas big-O of methodTwo is ((maxN -2)/2)^2.

Categories

Resources