Abraham Murciano Benzadon Abraham Murciano Benzadon - 4 months ago 13
HTML Question

setTimeout function not working with for loop

I'm trying to run this code to make a slideshow of 3 images, but it's not working properly. The slideshow runs once, but then just stops...

Below is my JavaScript, CSS and HTML, and if you run the code snippet you will see the slide show run once.

The HTML is basically declaring a container div with the slides as divs wth a specific background image. (For this question I changed the images to colors so you can see the slideshow in action)

The CSS declares the position of each of the images of the slideshow when it is in plain view and when it is hidden.

The JavaScript cycles through the slides giving each one a class of "hidden" when they are supposed to move out of view. At the end, it brings back the first slide by removing all the "hidden" classes.

I'm pretty sure the issue is in the JavaScript with the setTimeout function since whenever I run the functions in the console it works perfectly, but when I try to automatically set them to run in my JS it only runs once.



function slide1to2(){
document.getElementById('slide1').className = "hidden";
clearTimeout(s1to2);
}
function slide2to3(){
document.getElementById('slide2').className = "hidden";
clearTimeout(s2to3);
}
function slide3to1(){
document.getElementById('slide1').className = "";
document.getElementById('slide2').className = "";
clearTimeout(s3to1);
}

for(i=0; i<100; i++){
s1to2 = window.setTimeout(slide1to2, 2000);
s2to3 = window.setTimeout(slide2to3, 4000);
s3to1 = window.setTimeout(slide3to1, 6000);
}

div#slideshow{
width:100%;
height:50%;
background-image:url("white-wall.png");
}

div#slideshow div{
width:100%;
height:inherit;
background-repeat:no-repeat;
background-position:center;
background-color:rgba(0,0,0,0.5);
position:absolute;
transition:1s;
}

div#slideshow div[id$="1"]{
background:#FF8888;
transform:translateX(0%);
z-index:3;
}

div#slideshow div[id$="2"]{
background:#88FF88;
transform:translateX(0%);
z-index:2;
}

div#slideshow div[id$="3"]{
background:#8888FF;
transform:translateX(0%);
z-index:1;
}

div#slideshow div[id$="1"].hidden{
transform:translateX(-100%);
}

div#slideshow div[id$="2"].hidden{
transform:translateX(-100%);
}

<div id="slideshow">
<div id="slide1"></div>
<div id="slide2"></div>
<div id="slide3"></div>
</div>




Answer

When you setTimeout(), the code doesn't wait for the timeout to finish. That means that your for loop is executed 100 times after 2 seconds, another 100 times after 4 seconds, and another 100 times after 6 seconds.

Instead of that, you can re-set the timeouts after the third frame is finished.

An example of simple loop with timeouts:

var i = 0;
function a() {
   //Do some stuff
   if (i++ < 100) setTimeout(a, 1000);
}

This ^ is good. A bad example would be:

for (var i = 0; i < 100; i++) {
    setTimeout(function() {
        //Do stuff
    }, 1000);
}

The first will execute 100 times with interval of 1 second, the latter will execute 1 time.