1

Why does setTimeout not work inside a for loop? I'm trying to have a class added to each frame one at a time and every three seconds I need to remove it from the current one and add it to the next. When It gets to frame-6 I need it to wait ten seconds before removing the class. Then I need it all to repeat. But its just adding the class to them all straight away and then not removing them.

for(i = 1; i < 6; i++){
    jQuery('.frame-'+i).addClass('color');

    if(i < 6){
        setTimeout(function(){
            jQuery('.frame-'+i).removeClass('color');
        }, 3000);
    }else if(i = 6){
        setTimeout(function(){
            jQuery('.frame-'+i).removeClass('color');
            i = 1;
        }, 10000);
    }  
}
.color{
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="frame-1">one</div>
<div class="frame-2">two</div>
<div class="frame-3">three</div>
<div class="frame-4">four</div>
<div class="frame-5">five</div>
<div class="frame-6">six</div>

5
  • A for loop executes instantly, regardless of any timers in it's logic. I'd suggest you research setInterval() instead as it's far more appropriate for your needs. Commented Feb 6, 2018 at 10:55
  • 2
    It does work - it's doing exactly what you've told it to do, which is to create 6 timeouts, 5 that trigger in 3 seconds and 1 that triggers in 10. If you want something to happen at 3 seconds and then 6 seconds etc. then create timeouts for those intervals instead. Commented Feb 6, 2018 at 10:55
  • the loop doesn't wait for the timers to complete before continuing. The countdown happens separately from the moment you trigger it, in parallel to your other code. Commented Feb 6, 2018 at 10:57
  • Possible duplicate of Asynchronous Process inside a javascript for loop Commented Feb 6, 2018 at 10:57
  • when function inside setTimeout executes the value of i will be 7. Your code inside setTimeout will try to remove color class from frame-7. refer github.com/getify/You-Dont-Know-JS/blob/master/… Commented Feb 6, 2018 at 11:00

1 Answer 1

1

There are 2 issues with your code. Firstly, you're expecting the timeouts to execute before the next one is created, which is wrong. You're creating them all at the same time. Secondly, you're reusing the i variable inside the timeouts, so when they fire it's 6, for all of them.

However, you can make a recursive function to handle all of this, like this...

function timeoutHandler(i) {
  // if no value is passed, set i = 1
  if (!i) i = 1;
  
  // if i < 6 then create a setTimeout for 3 seconds
  // when we remove the class and call the function again with i + 1
  if (i < 6) {
    setTimeout(function() {
      $(".frame-" + i).removeClass("color");
      timeoutHandler(++i);
    }, 3000);
  }
  // else (i == 6) setTimeout for 10 seconds
  // when we remove the class and stop
  else {
    setTimeout(function() {
      $(".frame-" + i).removeClass("color");
    }, 10000);
  }
}

// add class to initialise - should really do this in html
for(i = 1; i < 7; i++) {
    $(".frame-" + i).addClass("color");
}

// start
timeoutHandler();
.color{
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="frame-1">one</div>
<div class="frame-2">two</div>
<div class="frame-3">three</div>
<div class="frame-4">four</div>
<div class="frame-5">five</div>
<div class="frame-6">six</div>

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.