JavaScript приостанавливает выполнение функции для ожидания ввода пользователя - PullRequest
9 голосов
/ 05 апреля 2011

Я пытаюсь сделать что-то вроде игры, используя холст HTML5, JavaScript и XML.Идея состоит в том, что вы можете сделать тест, поместив вопросы и ответы в XML-файл.Я написал основной цикл, который просматривает все вопросы, ставит их и проверяет правильность ответа.Сейчас я просто использую оповещения и диалоговые окна для ответа на вопросы. Проблема в том, что мой основной цикл - это одно большое взаимосвязанное целое, которое проходит всю игру от начала до конца, и вместо того, чтобы иметь блоки оповещений, представляющие вопросы, и диалоговые окнаответьте, сразу же за другим, я хочу, чтобы какое-то взаимодействие с пользователем.Ответы на вопросы отображаются в полях внизу экрана, и пользователь получает возможность управлять краном, чтобы выбрать правильный ответ.Вот фрагмент кода из основного цикла, на котором я застрял:

answer = loadQuestion(i);
            if (answer == "correct") {
                // answered correctly, update scoreArray and load next question
                scoreArray[currentQuestion] = "correct";
                // show 'next'-button and wait for press to continue

            } else {
                // answered incorrectly again, update scoreArray and load next question
                scoreArray[currentQuestion] = "error";
                // show 'next'-button and wait for press to continue

            }

Как видите, я вызываю loadQuestion, который мгновенно загружает вопрос, показывает возможные ответы и на данный момент сразу бросаетдиалоговое окно, где вы можете ввести ответ.Этот ответ возвращается и проверяется.

Я уже запрограммировал элементы управления краном, пользователь уже может забрать ящик с ним.Но поскольку я вызываю loadQuestion и ожидаю, что он вернет значение, это не работает.Как сделать так, чтобы мой основной цикл "приостановился", пока игрок не дал ответ, используя кран, и затем продолжил?Я уже пытался сделать ответ глобальной переменной и просто иметь пустую , а answer == "" , чтобы функция была занята, ничего не делая, пока answer не получит значение, но это просто замораживает скрипт.Я также возился с интервалами, пытаясь отслеживать состояние переменной ответа, очищать интервал и возвращать значение, когда это происходит, но это просто возвращает false, поскольку функция завершается без немедленного возврата значения.

Ответы [ 3 ]

19 голосов
/ 05 апреля 2011

Как сделать так, чтобы мой основной цикл "останавливался", пока игрок не дал ответ, используя кран, а затем продолжил?

Разбив его.Единственный «выход» в JavaScript в браузерах - это позволить вашей функции завершиться и затем организовать обратный вызов позже (через setTimeout, setInterval, обратный вызов ajax и т. Д.).В вашем случае я склонен думать, что триггером для вашего обратного вызова должно быть действие пользователя, отвечающее на предыдущий вопрос, например, обработчик click в полях ответов или что-то подобное (вместо setTimeout и тому подобное, котороеавтоматизированы).

Например, этот код:

function loopArray(ar) {
    var index;
    for (index = 0; index < ar.length; ++index) {
       doSomething(ar[index]);
    }
}

... можно преобразовать так:

function loopArrayAsync(ar, callback) {
    var index;

    index = 0;
    loop();

    function loop() {
        if (index < ar.length) {
            doSomething(ar[index++]);
            setTimeout(loop, 0);
        }
        else {
            callback();
        }
    }
}

Вторая версия возвращает управление обратнобраузер на каждой итерации цикла.Также важно отметить, что вторая версия возвращает до того, как циклы были завершены, тогда как первая версия ждет, пока все циклы не будут выполнены, поэтому вторая версия имеет callback функция, которую она вызывает после завершения цикла.

Код, вызывающий первый, может выглядеть следующим образом:

var a = ["one", "two", "three"];
loopArray(a);
// Code that expects the loop to be complete:
doTheNextThing();
doYetAnotherThing();

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

var a = ["one", "two", "three"];
loopArrayAsync(a, function() {
    // Code that expects the loop to be complete:
    doTheNextThing();
    doYetAnotherThing();
});

Делая это, вы, вероятно, обнаружите, что используете замыкания (loop, выше, это замыкание), и поэтому эта статья может быть полезна: Затворы не сложны

3 голосов
/ 05 апреля 2011

Синхронизация отсутствует.приостановленные инструменты ввода / вывода в браузере JS за исключением alert, confirm и prompt.Так как вы не хотите их использовать - попробуйте следующий шаблон:

loadQuestion(i, function(answer) {
   if (answer == "correct") {
            // answered correctly, update scoreArray and load next question
            scoreArray[currentQuestion] = "correct";
            // show 'next'-button and wait for press to continue

        } else {
            // answered incorrectly again, update scoreArray and load next question
            scoreArray[currentQuestion] = "error";
            // show 'next'-button and wait for press to continue

        }
  resumeGameExecution();
});

Т.е. когда пользователь отвечает на него - функция обратного вызова выполняется, и вы знаете, что все в порядке.

2 голосов
/ 05 апреля 2011

Насколько я понимаю, у вас есть приложение для анкетирования, где вы задаете ряд вопросов, а затем просите пользователя отбросить свой ответ с помощью некоторого элемента управления перетаскиванием (кран).пойти касательно и сказать, что дизайн кажется неправильным.Javascript основан на событиях, и наличие одного основного потока, зацикливающегося для взаимодействия с пользователем, снизит удобство использования.Я не буду использовать любой способ остановить поток (иначе в Java).Javascript не написан для такого варианта использования.Ваше приложение будет восприниматься как не отвечающее некоторым браузерам и почти всем анализаторам производительности (например, Yslow).

Таким образом, я бы поставил каждый вопрос с помощью div, идентифицируемого классом, который внутренне является последовательностью (question1..2).Первоначально только один вопрос будет включен или видим.Как только пользователь ответит на вопрос, я включу включенный вопрос.(о соответствующем событии, в этом случае возможно событие перетаскивания перетаскивания).Поскольку он последовательный, мне просто нужно проверить, ответил ли пользователь на вопрос 1, тогда я включу вопрос 2 соответствующим образом.Весь поток должен быть управляемым событиями.Событие здесь - это пользователь, отвечающий на вопрос.

...