30

I would like to create a pause inside a while loop so that I can create n animations that each appear 3 seconds after the other.

I've tried the following, but it doesn't work. Would love to have someone show me what I'm doing wrong.

i=0;
while (i < n) {
    someanimation();
    setTimeout(function(){
        i++;
    }, 3000);
     
};
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
djianp
  • 303
  • 1
  • 3
  • 4
  • Possible duplicate of [How do I add a delay in a JavaScript loop?](https://stackoverflow.com/questions/3583724/how-do-i-add-a-delay-in-a-javascript-loop) – Bergi Feb 23 '19 at 18:41

7 Answers7

45

setTimeout does not pause; it asks Javascript to run some other code later.

Googling for "setTimeout loop" tells you exactly what you need to know. If you look around a little bit, it even mentions setInterval. The difference: using setTimeout to loop will wait 3 seconds in between loops, whereas setInterval will make it take 3 seconds total for the loop (including however much time the animation takes, as long as it's less than 3 seconds :) ). Also, setInterval constructs an infinite loop that you'll have to break out of after the desired number of times; setTimeout requires you to construct the loop yourself.

i = 0;

// setTimeout approach
function animation_loop() {
  someAnimation();
  setTimeout(function() {
    i++;
    if (i < n) {
      animation_loop();
    }
  }, 3000);
};
animation_loop();

// setInterval approach
i = 0;
someAnimation();
iid = setInterval(function() {
  i++;
  if (i < n) {
    someAnimation();
  } else {
    clearInterval(iid);
  }
}, 3000);
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • 6
    you rock!! thank you so much - I'm a real beginner, so I'm not familiar with the idioms and I don't always know what are the best keywords to google. Anyway, you really unblocked me in a big way!! – djianp Dec 29 '10 at 02:06
  • This answer introduces an infinite `setInterval`. I'ts better to clear the `setInterval` when `i >= n`. – A1rPun Nov 01 '18 at 18:38
  • 1
    @A1rPun agreed; I updated the code to include that (and a bit clearer labelling of what's going on). – Karl Knechtel Apr 25 '21 at 16:04
11

setTimeout is a little trickier than that because it doesn't block (i.e. it doesn't finish waiting on the timeout before continuing with the program).

What you want is closer to this:

var i = 0;
function nextFrame() {
    if(i < n) {
        someanimation();
        i++;
        // Continue the loop in 3s
        setTimeout(nextFrame, 3000);
    }
}
// Start the loop
setTimeout(nextFrame, 0);

It may also be worth your while to read up on setInterval as a possible alternative.

psmay
  • 1,001
  • 7
  • 17
9

Well, thanks to ES6-7 with Promises we can now make a pause and make it look nice at the same time!

var id = 0;

async function do() {
  while(true) {
    await pause(id);
    //will happen only after pause is done
    id++; 
  }
}
function pause(id) {
  return new Promise(resolve => setTimeout(() => {
    console.log(`pause ${id} is over`);
    resolve();
  }, 1500)); 
}

do();
Telion
  • 727
  • 2
  • 10
  • 22
5

One of the way of doing it is to use RxJS. Please take a look at working example here

Rx.Observable
  .interval(1000)
  .take(10)
  .subscribe((x) => console.log(x))
Community
  • 1
  • 1
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
1

create a function like:

function sleep_until (seconds) {
   var max_sec = new Date().getTime();
   while (new Date() < max_sec + seconds * 1000) {}
    return true;
}

and then change your code to

i=0;
while (i < n) {
    someanimation();
    sleep_until(3);
    do_someotheranimation();
};
shankhan
  • 6,343
  • 2
  • 19
  • 22
0
function myFunction() {
    var x;
for(var i=0;i<10;i++){
    if (confirm("Press a button!") == true) {
        x = "You pressed OK!";
    } else {
        x = "You pressed Cancel!";
    }
    document.getElementById("demo").innerHTML = x;
}
}``
for
  • 1
0

You are not very specific about what you want to do, but I'd say the main problem is that you call someanimation() without a delay. So maybe this solves it for you:

for (var i = 0; i < n; i++) {
    setTimeout(someanimation, 3000 * i);
};

Note the missing () after someanimation as it is the callback for setTimeout().

sjngm
  • 12,423
  • 14
  • 84
  • 114
  • Please don't reinvent something for which there are standard idioms. – Karl Knechtel Dec 28 '10 at 17:54
  • @Karl Knechtel: what are you talking about? What "standard idioms"? Yours is the same idea. The only difference is that you launch the next call to `someanimation()` in the timer function. – sjngm Dec 28 '10 at 18:00
  • "...you launch the next call to someanimation() in the timer function." That's exactly what the standard idiom is. That way, only one callback is enqueued at a time. – Karl Knechtel Dec 28 '10 at 19:04
  • This will enqueue all of the iterations at the same time and then wait 3 seconds to dump out the calls to someanimation at the same time. – Brett Mathe Feb 19 '17 at 03:20
  • @BrettMathe You do understand how a for-loop works? So there is no way that all calls to `someanimation()` are performed at the same time. While Karl's comment make sense, yours is invalid. – sjngm Feb 19 '17 at 16:45
  • I thought it was obvious but what I meant by "at the same time" is relative and effectively the same time if someanimation is doing something trivial. I guess what I should say is that your code does not wait 3 seconds before calling each iteration of someanimation. Try it yourself and see. – Brett Mathe Feb 20 '17 at 20:19
  • 1
    @BrettMathe \*sigh\* https://jsfiddle.net/fw4mmgca/ Just watch the timestamp. And please get your facts straight, before you downvote the next time. – sjngm Feb 21 '17 at 12:55
  • Nah seems more like a hack because you're actually enqueuing them all at the same time, just at increasing intervals (3 seconds, then 6 seconds, then 9 seconds...). It's gross. – Rambatino Mar 08 '18 at 13:56