1

I'm making a simple dice game, and I have set up a function that will randomly generate numbers and display them very quickly to simulate a sort of die being rolled. The problem I'm having is that I want to wait until the simulation is complete before I return the value, but instead the value is returned right away. Can anyone point me in the right direction? Essentially I want rollDie() to wait for diceSimulation() to be complete before continuing.

function rollDie(){

     diceSimulation();
     var result = Math.floor(Math.random() * 6) + 1;
     document.getElementById("result").innerHTML = result;
     return result;

}

function diceSimulation(){
     for (var i = 0; i < 30; i++) {
         var random; 
         (function (i) {
             setTimeout(function () {
                 random = Math.floor(Math.random() * 6) + 1;
                 document.getElementById("result").innerHTML = random;
             }, 50*i);
         })(i);
     }
}

2 Answers 2

4

One option would be for diceSimulation to return a Promise that resolves after 50 * 31 ms, and for rollDie to await it:

async function rollDie(){

  await diceSimulation();
  var result = Math.floor(Math.random() * 6) + 1;
  document.getElementById("result").innerHTML = result;
  return result;

}

function diceSimulation(){
  return new Promise((resolve) => {
    for (var i = 0; i < 30; i++) {
      (function (i) {
        setTimeout(function () {
          const random = Math.floor(Math.random() * 6) + 1;
          document.getElementById("result").innerHTML = random;
        }, 50*i);
      })(i);
    }
    setTimeout(resolve, 1530);
  });
}

Note that rather than (function (i) { inside the loop, you might consider just using let instead of var, it's far nicer to read and debug. (Using var has too many problems - best to use const or let instead, whenever possible.) It would also be more elegant to select result once inside diceSimulation, rather than on every iteration of the loop, and unless you're deliberately inserting HTML markup, better to assign to testContent rather than innerHTML:

const result = document.getElementById("result");
for (let i = 0; i < 30; i++) {
  setTimeout(() => {
    const random = Math.floor(Math.random() * 6) + 1;
    result.textContent = random;
  }, 50*i);
}

Live demo:

async function rollDie() {

  await diceSimulation();
  var result = Math.floor(Math.random() * 6) + 1;
  document.getElementById("result").innerHTML = result;
  return result;

}

function diceSimulation() {
  return new Promise((resolve) => {
    const result = document.getElementById("result");
    for (let i = 0; i < 30; i++) {
      setTimeout(() => {
        const random = Math.floor(Math.random() * 6) + 1;
        result.textContent = random;
      }, 50 * i);
    }
    setTimeout(resolve, 1530);
  });
}

rollDie();
<div id="result"></div>

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

7 Comments

When I run this, the simulation still runs after I have displayed the result from rollDie(). It's almost like it waits till right after the result has been displayed to do the simulation
If you change the i < 30 number, or the }, 50 * i number, you'll have to change the 1530 number appropriately - otherwise, resolve should be called after all timeouts in the for loop have finished. Actually, since the final action is the same as the loop action, why not leave out the final action entirely, and iterate from 0 to 30 instead of from 0 to 29?
I didn't change anything, just pasted it in and it was doing that. I see the result displayed and then I see the simulation. It looks like rollDie() is actually returning [object Promise] instead of a number as well.
In order to consume Promises you have to call .then on them (or await them, as in the answer). See edit, seems to work just fine to me
Hmmm I'm still having the problem. Does it matter that I'm calling rollDie() from another function? Do I have to do another await?
|
1

You can achieve your expected result using a callback or a promise . A simple example below shows how you can use promises as a solution :

let diceSimulation = () => {
console.log("Dice simulation complete");
};
let rollDie = new Promise((resolve,reject)=> {
resolve("Roll die is completed");
})

rollDie.then((message)=> {
    console.log(message);

    diceSimulation();
},
(fail)=> {

})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.