0

I need help getting my image slideshow to work properly. I set it up to loop over an array of images and display each one in 5 second intervals. What it actually does is loop over the entire array but only displays the last image. Code below:

const imgArray = ['http://media.tumblr.com/tumblr_lf88gg6J5d1qamm7n.jpg',
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR5SG1QIHcwLM9FNPFOO0IvFBNJ9CJCGZ-iGz7zfmfhTypEqqTU','https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQRZLiRBwwBBMAapL5IzxqoV-zskYuGD9lWvyirUryKjVaRqwlO'];
let index = 0;

function autoChange() {
  let img = document.getElementById('img');
  let arrayIndex;
  for (arrayIndex = 0; arrayIndex < imgArray.length; arrayIndex++) {
    img.src = imgArray[arrayIndex];
    setTimeout(autoChange, 3000);
    console.log(imgArray[arrayIndex]);
  }
  arrayIndex++;
  if(arrayIndex > imgArray.length) {
    arrayIndex = 0
  };
}

autoChange();
<section>
  <figure>
    <img id='img' class='displayed-img' width="350" src="imgs/pic0.jpg">
  </figure>
</section>

Thank you.

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
wkmfos
  • 3
  • 3
  • On each `autoChange()` request you are looping over all the images, which in turn leads to all the images being loaded very quickly but ending on the last one. And this is what you are seeing. What you need to do is keep track of the image that is load, check for the next one and load that. If no next image, go back to the start (hint: no loop needed). – Tigger Jun 10 '18 at 23:43
  • @baao yes, you're right! – Ele Jun 10 '18 at 23:44
  • The issue is that you might expect the `setTimeout` to be _blocking_, meaning it’ll wait the three seconds before continuing with the next iteration, which it will _not_. – Sebastian Simon Jun 10 '18 at 23:45
  • you will always have the last value simply because after 3 seconds index will be incremented. you can use closure in this situation. – Stakvino Jun 10 '18 at 23:56
  • @Stakvino `index` is never actually used in the OPs code beyond initializing it to `0` so it will stay `0` the entire time. `arrayIndex` will become 3 almost immediately (not after 3 seconds). – Scott Marcus Jun 11 '18 at 00:36
  • i didn't mean it requires 3 seconds i meant that after 3 seconds the loop will be over for sure. – Stakvino Jun 11 '18 at 00:44

2 Answers2

0

JavaScript runs in a single-threaded environment (only one task can be executing at any given moment). You are trying to "slow down" your loop with a timer, but the timer's callback function will only execute after the current function (and all other code on the call stack) have finished. So, your loop runs to completion and then the timer is called.

As such, you shouldn't try to use a timer inside of a loop. Instead, keep a counter outside of the scope of your function and increment it upon each function call. Then, have the timer call the function all over again - this creates the looping effect you are looking for without the actual loop.

const imgArray = ['http://media.tumblr.com/tumblr_lf88gg6J5d1qamm7n.jpg',
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR5SG1QIHcwLM9FNPFOO0IvFBNJ9CJCGZ-iGz7zfmfhTypEqqTU','https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQRZLiRBwwBBMAapL5IzxqoV-zskYuGD9lWvyirUryKjVaRqwlO'];

let index = 0;  // This will keep track of the current array index to use
let img = document.getElementById('img'); // Get your reference just once, not on each function call

function autoChange() {
  // You only need to ensure that the index isn't out of bounds
  if(index < imgArray.length){
    img.src = imgArray[index];      // If not, use the index
    index++;                        // Then, increment it
    console.clear();
    console.log(imgArray[index]);
  } else {
    index = 0;  // If so, reset the index
  }
  // Now that the right image is showing, wait 3 seconds and call the function all over again
  setTimeout(autoChange, 3000);  
}

autoChange();
<section>
  <figure>
    <img id='img' class='displayed-img' width="350" src="imgs/pic0.jpg">
  </figure>
</section>
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
-2

you were at the right track, made little changes

const imgArray = ['http://media.tumblr.com/tumblr_lf88gg6J5d1qamm7n.jpg',
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR5SG1QIHcwLM9FNPFOO0IvFBNJ9CJCGZ-iGz7zfmfhTypEqqTU','https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQRZLiRBwwBBMAapL5IzxqoV-zskYuGD9lWvyirUryKjVaRqwlO'];
var index = 0;

function autoChange() {
  let img = document.getElementById('img');
  if (index >= imgArray.length)
  index = 0;
  else index++
  
 img.src= imgArray[index] 

 setTimeout(autoChange, 3000);
}

autoChange();
<section>
  <figure>
    <img id='img' class='displayed-img' width="350" src="imgs/pic0.jpg">
  </figure>
</section>
Alen.Toma
  • 4,684
  • 2
  • 14
  • 31
  • 1
    Answers on Stack Overflow should explain the problem and the proposed solution. Additionally, poor coding habits in answers should be avoided. You are omitting the brackets `{}` around your `if` branches and some semi-colons. While legal syntax, both are well known to be bad practices as they both can lead to bugs. – Scott Marcus Jun 10 '18 at 23:53
  • man you are to much, np for down voting – Alen.Toma Jun 12 '18 at 02:23
  • *man you are to much* As long as that is your point of view, I think your "answers" will continue to be down voted. Try to understand what Stack Overflow actually is.. – Scott Marcus Jun 12 '18 at 13:04