Я создаю игру на угадывание с Node JS. После сбора некоторых данных на сервере я отправляю их на сервер, и игра начинается. Данные содержат все 10 уровней, поэтому игра может запускаться на одной странице. Каждый уровень длится 10 секунд. После истечения времени выбор пользователя отправляется на сервер, и результат возвращается. Ответ отображается, а затем содержимое изменяется на «следующий уровень» (используя содержимое в большом объекте данных, поэтому обновление не требуется).

У меня есть некоторые проблемы с 10 уровней запуска по 10 секунд каждый (или ~ 12 секунд с задержкой для отображения результатов).

Это не может быть сделано в каком-то цикле, так как все awaits для каждого уровня будут выполняться одновременно. Например:

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

for (let i = 0; i < 10; i++) {
    displayPage(i);
    await timeout(10000);
    const result = await $.post(...) // gets results
    displayResults(result);
    await timeout(2000);
}

Все timeout будут работать одновременно, и это не сработает.

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

На данный момент я получил следующий результат:

displayPage(level1);
await timeout(10000);
const result = await $.post(...)
displayResults(result);
await timeout(2000);

displayPage(level2);
await timeout(10000);
const result = await $.post(...)
displayResults(result);
await timeout(2000);

displayPage(level3);
await timeout(10000);
const result = await $.post(...)
displayResults(result);
await timeout(2000);

displayPage(level4);
await timeout(10000);
const result = await $.post(...)
displayResults(result);
await timeout(2000);

...

Это не кажется эффективным, и я думаю, что есть лучший способ сделать это, но я не уверен, как. Мы ценим любые предложения. Благодарность!

0
Ethan 28 Окт 2019 в 00:08

3 ответа

Лучший ответ

Я думаю, это то, что вы ищете:

const pages = [1, 2, 3, 4, 5];

run();

async function run() {
  for (let i = 0; i < pages.length; i++) {
    await displayPage(i);
    const result = 'Some result';
    await displayResult(result);
  }
}

function displayPage(number) {
  text.innerText = 'Page ' + number;

  return new Promise(res => {
    setTimeout(res, 10000);
  });
}

function displayResult(result) {
  text.innerText = 'Result: ' + result;

  return new Promise(res => {
    setTimeout(res, 2000);
  });
}
<div id="text"><div>

Другое решение, без обещаний и петель:

const pages = [1, 2, 3, 4, 5];
let currentPageIndex = 0;

displayPage();

function displayPage() {
  const index = currentPageIndex++;
  if (pages[index] === undefined) return;

  const pageNumber = pages[index];

  text.innerText = 'Page ' + pageNumber;

  const result = 'Some result';

  setTimeout(() => {
    displayResult(result);
  }, 10000);
}

function displayResult(result) {
  text.innerText = 'Result: ' + result;

  setTimeout(() => {
    displayPage();
  }, 2000);
}
<div id="text"></div>
0
Andrew Dashkov 27 Окт 2019 в 22:38

Используйте setInterval на 1000 мс, чтобы создать работника и добавить конечный автомат, который переключает воспроизведение (10 с) и ожидание (2 с). Вам нужна процедура, которая выполняет пост-вызов на сервер и объект для хранения данных (уровней и прочего).

Например:

setInterval(funcWorker,1000,s_gameObj);



 function funcWorker(f_context){
    var l_dateNow = new Date();
    if(f_context.is_playing){
       var l_elapsed = l_dateNow.getTime() - f_context.dateLevelStart.getTime();
       if(l_elapsed.totalSeconds() >= f_context.LEVEL_TIME){

           f_context.end_level();
       }
    }else if(f_context.is_waiting_user){
       //same check as above but on the waiting start 
        ....
         f_context.next_level();


    }else if(f_context.is_waiting_server){
       //do whatever
    }
}

End_level () должен установить флаг состояния в объекте context (game) для отправки и отправки на сервер. Когда сервер вернется в функцию ответа, установите состояние ожидающего пользователя и инициируйте соответствующую переменную времени в now (). Функция next_level () должна установить состояние воспроизведения и инициировать соответствующую переменную времени для now (), чтобы таймер мог считать. Рассматривайте приведенный выше код как ссылку, а не как ресурс копирования-вставки.

0
t.stv 27 Окт 2019 в 21:45

Кажется, ваш первый вариант работает, если он заключен в асинхронную функцию:

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
const testFunc = async () =>{
  for (let i = 0; i < 10; i++) {
      console.log('page' , i+1 , '- question')
      await timeout(3000);
      console.log('page' , i+1 , '- answer')
      await timeout(1000);
  }
}
testFunc()
0
Willman.Codes 27 Окт 2019 в 21:27