kawnah
kawnah

Reputation: 3404

Set a timeout within a loop

How specifically is it best to go about setting a timeout within a for loop? I have a square that upon click, the expected result is that it ticks down 1px every 500 ms. I'm attempting to do this by setting the CSS value of the top property to i and wrapping in a timeout of 500 ms.

What is happening is it "hangs" on what looks like a first few pixels before launching straight to bottom.

What I have so far is below:

$("#rect").click(function() {
 	for (i = 0; i < 200; i++) {
    	(function(i){
      	setTimeout(function() {
        $("#rect").css("top", i) 
        }, 500);
      })(i); 
  } 	
});

$("#reset").click(function() {
  	$("#rect").css("top", "0"); 
});
#rect {
  position: absolute;
  top: 0;
  width: 200px;
  height: 50px;
  background-color: #333;
}

#rect:hover {
  cursor: pointer;
}

#reset {
  float: right;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="rect"></div>

<button id="reset">reset</button>

Howcome stating the top property value of i in a timeout within the loop doesn't work?

Upvotes: 0

Views: 159

Answers (4)

karthick
karthick

Reputation: 12176

Your timing function is wrong change it to 500*i; if you want it to move every single iteration.

At present all your setTimeOuts fire at 500ms that's why it jumps

$("#rect").click(function() {
    for (let i = 0; i < 200; i++) {
        setTimeout(function() {
        $("#rect").css("top", i); 
        }, 500*i); 
  }     
});

$("#reset").click(function() {
    $("#rect").css("top", "0"); 
});

But you can use lot of other solutions as mentioned in the other answers. Animate, slide up all are more robust.

Upvotes: 1

dug
dug

Reputation: 340

It looks like you're creating 200 timeouts that all run at the same time and each bump the element down a pixel giving the appearance that it shoots down.

What you're wanting is closer to this. Set an interval to run your function that moves the box every 500ms:

setInterval(moveBox, 500);
var boxMovedTimes = 0;

function moveBox() {
  $('#rect').css('top', boxMovedTimes + "px");
  boxMovedTimes += 1;
  console.log('moved ' + boxMovedTimes)
}

Upvotes: 0

JohnPan
JohnPan

Reputation: 1210

I did not check your code, but uf you need to move a rectangle and you are already use jQuery, you may as well use jQuery sliding efects https://api.jquery.com/category/effects/sliding/

An example:

$( "#book" ).slideUp( "slow", function() {
    // Animation complete.
  });

Sometimes it is hard to create a simple effect like this, since it has to do with how the browser renders very fast changes on painting

Upvotes: 0

Antoine Bouchard
Antoine Bouchard

Reputation: 55

You setTimeout is in an anonymous function, so the loop calls the function and gets to the next iteration, setting the timeouts almost all at once.

Also, you might want to use setInterval to do that. It repeats the callback multiple times.

https://www.w3schools.com/jsref/met_win_setinterval.asp

Upvotes: 0

Related Questions