Завершение подфункции с помощью цикла setTimeout перед функцией

Я уже несколько ночей боролся с проблемой времени в моем коде и не могу придумать правильное решение.

Описание псевдокода:

// прослушиватель событий на кнопке запускает бросок кубика при каждом нажатии

// вызываем функцию анимации // генерировать случайные значения x количество раз // отображаем каждый результат с помощью setTimeout // запускаем код для определения окончательного "установленного" значения и отображения результатов

HTML:

<!DOCTYPE html>

<html lang = "en">
  <meta charset = "utf-8">
<head>
  <title>Make Cards</title>
</head>
<body>

  <p>Total:<span id = "total"></span></p>
  <div id = "contain">

  <div class = "die"></div>
  <div class = "die"></div>
  <div class = "die"></div>
  <div class = "die"></div>
  <div class = "die"></div>
  <div class = "die"></div>

    <br>

  <button id = "rollBtn">Roll</button>
  <input type = "number" value = "1" min = "1" max = "6" id = "numDice">

  </div>

</body>
</html>

Javascript:

var diceValue = ["&#9856", "&#9857", "&#9858", "&#9859", "&#9860", 
"&#9861"];
var dice = document.querySelectorAll(".die");
// select number of dice
var numDice = document.querySelector("#numDice");
// convert string to value
var newNumDice = Number(numDice.value);
var roll = document.querySelector("#rollBtn");
var total = document.querySelector("#total");


// make animation function
// call animation function


init();

function init(){
  displayDice();
  }
//THIS IS THE BUTTON LISTERNER
roll.addEventListener("click", function(){
//THIS SHOULD RUN BEFORE THE REST OF THE FUNCTION (BUT DOESN'T SEEM TO)
  animate();
  var subTotal = 0;
  for (var i = 0; i < newNumDice; i++){
    var value = generateRandomDice() 
    dice[i].innerHTML = diceValue[value];
    subTotal = subTotal + (value+1);
    total.innerHTML = subTotal;
  }      
  for (var i = 0; i < 6; i++){
    dice[i].style.color = "black";
  }
                      })


numDice.addEventListener("click", function(){
  total.innerHTML = "-";
   newNumDice = Number(numDice.value);
  resetDice();
  displayDice();
  // console.info(Number(numDice.value));
})

function resetDice(){
  for (var i = 0; i < diceValue.length; i++){
    dice[i].innerHTML = "";
  }
}

// only display chosen number of dice

function displayDice(){
  for (var i = 0; i < newNumDice; i++){
    dice[i].innerHTML = diceValue[i];
  }
}

function generateRandomDice(){
  var dieSide = Math.floor(Math.random() * 6);
  return dieSide;
}

//ATTEMPT AT WRITING CODE FOR ANIMATION
function animate(){
  for (var i = 0; i < 50000; i++){
  var ani = setTimeout(rolling, 650);
  }
  }

function rolling(){
                for (var i = 0; i < newNumDice; i++){
    var value = generateRandomDice() 
    dice[i].innerHTML = diceValue[value];
    dice[i].style.color = "grey";
}
}

Не уверен, что происходит, но мне кажется, что animate (); код не запускается, пока не завершится остальная часть eventListener. Любая помощь - это здорово, спасибо.

Что не работает? Я запустил ваш код, и похоже, что он делает то, что вы хотите.

Marc 01.05.2018 23:17

Исходный код не синхронизировался. Я удалю свой комментарий, потому что он был исправлен с помощью приведенного ниже ответа.

Axfinger 02.05.2018 00:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
2
38
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что вы ждете завершения асинхронного кода, прежде чем выполнять синхронный код. Каждый раз, когда вы вызываете setTimeout, он сохраняет функцию, которую нужно вызвать, когда она будет готова к вызову (что составляет 650 мс от «сейчас»!).

Чтобы исправить, вы можете await, чтобы ваша анимация закончилась. Вот как я заставил его работать с вашим кодом:

Измените animate на:

function animate() {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < 50000; i++) {
      setTimeout(() => {
        rolling();

        if (i == 49999)
          resolve();
      }, 650);
    }
  });
}

а затем вы можете дождаться разрешения обещания, изменив свой прослушиватель кликов на это:

roll.addEventListener("click", async function() {
  await animate();
  var subTotal = 0;
  for (var i = 0; i < newNumDice; i++) {
    var value = generateRandomDice();
    dice[i].innerHTML = diceValue[value];
    subTotal = subTotal + (value + 1);
    total.innerHTML = subTotal;
  }
  for (var i = 0; i < 6; i++) {
    dice[i].style.color = "black";
  }
});

Результат, показанный позже, был для меня правильным.

Надеюсь, это поможет!

Promise получает довольно хорошую поддержку и может быть полифиллирован при необходимости (например, для поддержки IE11). async/await - это es2017, гораздо более новое дополнение, чем Promise. Большинство вечнозеленых браузеров имеют приличную поддержку, но если вам нужна более старая поддержка браузеров, ее нельзя заполнить полифиллами. Чтобы использовать его, вам придется перенастроить код. Если это проблема, вы можете использовать синтаксис Promise.then().catch(). Или вы можете (вздрогнув) использовать обратный вызов, если не хотите беспокоиться о полифилле.
David784 01.05.2018 23:37

Что ж, сначала позвольте мне сказать спасибо за исправление моего кода. Это действительно исправляет это, как вы предлагаете. Я знал об обещании, но не ожидал, что, похоже, является настоящим решением с точки зрения времени. Не думаю, что я полностью все это понимаю, но это будет моей домашней работой на потом. Теперь мне нужно кое-что исправить, чтобы на броски 6 кубиков не требовалось в 6 раз больше времени, чем для броска одного кубика.

Axfinger 02.05.2018 00:04

Другие вопросы по теме