#javascript #pausing-execution
#javascript #приостановка выполнения
Вопрос:
Я пытаюсь создать что-то вроде игры, используя HTML5 canvas, 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 и ожидаю, что он вернет значение, это не работает. Как мне заставить мой основной цикл «приостановиться» до тех пор, пока игрок, использующий кран, не даст ответ, а затем продолжить? Я уже пытался сделать ответ глобальной переменной и просто использовать пустое значение while answer == «», чтобы функция была занята, ничего не делая, пока answer не получит значение, но это просто замораживает скрипт. Я также возился с интервалами, пытаясь отслеживать состояние переменной ответа, а также очищать интервал и возвращать значение, когда это происходит, но это просто возвращает false, поскольку функция завершается без немедленного возврата значения.
Ответ №1:
Как мне заставить мой основной цикл «приостановиться» до тех пор, пока игрок, использующий кран, не даст ответ, а затем продолжить?
Разбивая ее. Единственный «выход» в 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
выше приведено замыкание), и поэтому эта статья может быть полезной: Замыкания не сложны
Комментарии:
1. @Diodeus: О, вы знаете, что говорят: «Прошлая производительность не гарантирует будущих результатов»…
2. Спасибо за ответ, я все еще начинающий JavaScripter и никогда раньше не использовал функции обратного вызова. Спасибо за четкое объяснение и пример кода 🙂 Вы получаете принятый ответ, поскольку это ответило на мой первоначальный вопрос. doc_180 тоже был прав, хотя, я думаю, мне лучше вернуться к чертежной таблице для некоторого переосмысления.
3. @Jort: Рад, что помогло. И да, я бы также посмотрел на более крупную структуру. 🙂
Ответ №2:
Синхронизация отсутствует. приостановлены инструменты ввода / вывода в браузере 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();
});
Т.е. когда пользователь отвечает на него — выполняется функция обратного вызова, и вы знаете, что все готово.
Комментарии:
1. Спасибо за четкое объяснение, я бы проголосовал за полезность вашего ответа, если бы у меня была репутация, позволяющая это сделать 🙂
Ответ №3:
Насколько я понимаю, у вас есть приложение для опроса, в котором вы задаете ряд вопросов, а затем просите пользователя сбросить свой ответ, используя какой-либо элемент управления перетаскиванием (кран).
Я собираюсь перейти к касательной и сказать, что дизайн кажется неправильным. Javascript основан на событиях, и наличие одного основного потока, выполняющего цикл взаимодействия с пользователем, приведет к снижению удобства использования. Я не буду использовать какой-либо способ остановки потока (он же в Java). Javascript написан не для такого случая использования. Некоторые браузеры и почти все анализаторы производительности (например, Yslow) будут воспринимать ваше приложение как не отвечающее на запросы.
Поэтому я бы предоставил каждому вопросу div, идентифицируемый классом, который внутренне является последовательностью (вопрос1..2). Изначально будет включен или виден только один вопрос. Как только пользователь ответит на вопрос, я включу разрешенный вопрос. (при соответствующем событии, в данном случае, вероятно, при перетаскивании). Поскольку это последовательный процесс, мне просто нужно проверить, ответил ли пользователь на вопрос1, затем я соответствующим образом включу вопрос2. Весь поток должен управляться событиями. Событием здесь является пользователь, отвечающий на вопрос.
Комментарии:
1. В этом вы определенно правы. Просматривая мой код, первоначальный одиночный цикл был хорош для начального тестирования, но я думаю, что мне лучше просто выбросить его и сделать более управляемым событиями, как вы сказали.