8

Is it possible to apply a delay to successive iterations of a javascript for-loop using jQuery or underscore? I have a for-loop on my page that I am using to pop up growl notifications when users fulfill certain conditions and if there are multiple conditions I would like to stagger the growl notifications instead of popping up several at the same time. Here is the loop in question:

var badge_arr = response.split("Earned badge:");
//Start at 1 so I'm not getting everything before the first badge
for(i = 1; i < badge_arr.length; i++){
    responseStr += badge_arr[i];
    //Create growl notification
    //badge info echoed back will be of the form 
    //Earned badge: name: description: imgSource
    var badge_info = badge_arr[i].split(':');
    var title = 'NEW BADGE UNLOCKED';
    var text = 'You just unlocked the badge '+badge_info[0]+': '+badge_info[1];
    var img = badge_info[2];
    createGrowl(title, text, img);
} 
jaimerump
  • 882
  • 4
  • 17
  • 35
  • Well dang, I was just about to accept the other answer before it was deleted. – jaimerump Aug 01 '12 at 18:11
  • @Xander The first element executed immediately for me, and then the rest executed at the same time. I saw that it worked in your JSfiddle correctly though. I have no idea what is up with that. But then again he had to change the parameters of the question, and your solution clearly works, at least for alerts. I'll just assume that I made a mistake implementing it, misplaced braces or something. – jaimerump Aug 01 '12 at 18:59
  • 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) – melpomene Dec 26 '18 at 13:54

2 Answers2

32
for(i = 1; i < badge_arr.length; i++){
    (function(i){
        setTimeout(function(){
            responseStr += badge_arr[i];
            //Create growl notification
            //badge info echoed back will be of the form 
            //Earned badge: name: description: imgSource
            var badge_info = badge_arr[i].split(':');
            var title = 'NEW BADGE UNLOCKED';
            var text = 'You just unlocked the badge '+badge_info[0] +
                       ': '+badge_info[1];
            var img = badge_info[2];
            createGrowl(title, text, img);
        }, 1000 * i);
    }(i));
}

Illustration:

for(i = 1; i <= 8; i++){
    (function(i){
        setTimeout(function(){
            document.body.innerHTML += i + "<br/>"
        }, 1000 * i);
    }(i));
} 
Alex
  • 34,899
  • 5
  • 77
  • 90
  • 1
    damn was about to point out your error with the lack of `* i` - you edited it before I could... +1 just for that! – ClarkeyBoy Aug 01 '12 at 17:56
  • Can you explain why the * i matters? – Tim Mar 02 '13 at 02:47
  • 1
    @tim if you run the example it'll become a-little more evident. the outer loop increments `i` `badge_arr.length` times. thus passing into the inner closure `0`, `1`, `2`, etc ... making the `setTimeout` execute every second (`1000` milliseconds). – Alex Mar 02 '13 at 03:56
  • 1
    @Xander, I found this when looking for 'delay in for loop javascript' on google. This function saved me a lot of worries, thanks a lot! – webketje May 13 '13 at 17:12
  • Why can't we have something like sleep? – Gaurav Ojha Dec 13 '16 at 13:43
4

I prefer to use self-invoking function that receives a number of iterations:

(function loop(i) {          
   setTimeout(function () {   

      console.log('hello world'); // your code

      if (--i) loop(i); // iteration counter
   }, 5000) // delay
})(10); // iterations count 
Andrei
  • 42,814
  • 35
  • 154
  • 218