JS die roll simulation with 6 die images

in Js, I want to try to simulate a die roll by showing images of die 1 to 6, but when I try to display these in a for loop, it only displays image dice6. I tried putting in a nested for loop to slow down the outer loop but that didnt work. Does the page need to refresh after changing "src" attribute?

const dieImage = function (num) {
      return "images/dice" + String(num).trim() + ".png";
    };

function dieRoll(num) {
        
          for (let i = 1; i < 7; i++) {
            for (let z = 0; z < 44444; z++) {} // attempt to slow
        
            if (num === 1) {
              img1.setAttribute("src", dieImage(i));
            } else {
              img2.setAttribute("src", dieImage(i));
            }
          }
        }

As mentioned in the comments you can use setTimeout. You can introduce a delay and give the browser a chance to redraw by using setTimeout, promise, and await, for example like this:

const DELAY = 300; // 300ms

async function dieRoll(num) {
  for (let i = 1; i < 7; i++) {
    if (num === 1) {
      img1.setAttribute("src", dieImage(i));
    } else {
      img2.setAttribute("src", dieImage(i));
    }

    await new Promise((resolve) => setTimeout(() => resolve(), DELAY));
  }
}

The loop execution will stop until the promise is resolved, but it will let the browser to continue to respond and redraw. When the promise is resolved after the timeout callback is run after the given DELAY milliseconds, the next iteration of the loop will take place.


What you are missing (roughly) is that the browser paints the screen when the JavaScript code has finished running. Even though you are setting the src attribute to a different image in a loop, the JavaScript code finishes only when the loop ends. The browser paints only once, i.e. the last image you set in the loop. This explanation may be oversimplified, but it gives you an idea.

The solution is to return from the JavaScript code after setting the src and repeating after a suitable delay, giving the user the opportunity to sense the change. setTimeout is probably good enough for your case; in other use cases where you want really smooth animation, there would be other solutions (e.g. requestAnimationFrame()). An untested implementation to demonstrate the intent:

function dieRoll(selectedNum) {
  var counter = 8; // how many times to change the die
  function repeat() {
    if (counter === 1) {
      // on the last iteration, set the image representing the selected number
      img1.setAttribute("src", dieImage(selectedNum));
    } else {
      // else decrement the counter, set a random image and repeat after a timeout
      counter--;
      img1.setAttribute("src", dieImage(Math.floor(6 * Math.random()) + 1));
      setTimeout(repeat, 300);
    }
  }
  repeat();
}