Тайна управления массивом JavaScript - PullRequest
0 голосов
/ 29 июля 2011

Приготовьтесь к запутанному объяснению. Я делаю глупый маленький сайт викторины. Пять вопросов на странице. Ответы хранятся в XML-файле. Вопросы отображаются игрокам по одному с вводом, чтобы они могли ответить. Когда игрок делает предположение о конкретном ответе, JQuery отправляет предположение в php-файл, который сравнивает ответ с тем, что хранится в xml, и возвращает либо 1 (правильно), либо 0 (неправильно). Сообщение инициируется событием keyup ввода текста.

У меня есть глобальный массив с именем Осталось , в котором хранятся вопросы на странице, ответы на которые еще не получены. Это заполняется при загрузке страницы значениями [1, 2, 3, 4, 5]. Если на вопросы правильно ответили, соответствующий номер удаляется. Поэтому, если игрок ответит на первый вопрос, , оставшиеся будут содержать [2, 3, 4, 5].

var current;
var remaining;

$(document).ready(function() {

    // What question the player is on.
    current = 1; 

    // Questions unanswered.
    remaining = new Array(1, 2, 3, 4, 5);

    $('#in').keyup(function() {
        // Send answer to server to check if it's right.
        CheckGuess($(this).val());  
    });

});

function CheckGuess(guess) {

if (guess.length > 2 && guess.length < 100) 
{
    $.post( 
        "class/check.php",
        "current=" + current + "&answer=" + guess,
        function(check) {

             if (check == 1) {
                    AnswerCorrect();
             }

        },
        "json"
    );
}   
}

function AnswerCorrect() {

// User guessed correctly.

if (remaining.length != 1) {

    var next;

    // Remove complete question from array of remaining values.
    for (var i = 0; i < remaining.length; i++ ) {
        if (remaining[i] == current) {          

            // Set the next question. It will be the next one in the array 
            // or the previous if the current question is the last in the array.
            if (i != (remaining.length - 1)) {
                next = remaining[i + 1];
            } else {
                next = remaining[i - 1];
            }

            debugger;

            // Remove current question.
            remaining.splice(i, 1);

            // Get out of the for loop.
            break;

        }           
    }   

    // Set current as next.
    current = next;

    // Set the href for the next question.
    var destination = "#m" + next;

    // Scroll to next question.
    $.scrollTo($(destination), { duration: 1000});

    // Clear input box.
    $("#in").val("");

}

else {
    // Quiz complete.
}

}

Все это работает в некоторой степени. Но у меня ужасные проблемы с какой-то загадочной проблемой. Я прошел через FireBug и, похоже, что это так:

  • (а). Страница загружается. Я вижу, что оставшиеся имеют значения [1,2,3,4,5], как я хочу.
  • (б). Игрок вводит правильный ответ на первый вопрос. «1» затем удаляется из , оставаясь , поэтому он имеет значения [2,3,4,5], как и ожидалось.
  • (с). Игрок вводит правильный ответ на второй вопрос, но теперь, как только FireBug достигнет любой точки останова, которую я установил, я вижу, что оставшиеся имеют значения [3,4,5]. Поэтому до того, как функция AnswerCorrect () вызывается, 2 исчезла. Куда делись 2 ?! Затем, когда AnswerCorrect () действительно запускается, он думает, что игрок находится на вопросе 3 (потому что , оставшийся содержит [3,4,5]). Общий результат заключается в том, что когда игрок отвечает на вопрос 2, и 2, и 3 помечаются как правильные.

Надеюсь, мое объяснение было несколько ясным. Я никогда не понимал ничего меньше в своей жизни. Я не понимаю, что происходит между пунктами (b) и (c) выше. Я перебираю код и не могу найти, где оставшихся сбрасывает «2». FireBug подводит меня. Кажется, что-то не ломается, когда должно. Если у меня есть точка останова на split () , я не вижу, чтобы удаление 2 могло происходить без моего наблюдения. У кого-нибудь есть подсказка? Я очень ценю любую помощь, прежде чем сойду с ума.

РЕДАКТИРОВАТЬ - Подробнее

(Извините за медленный ответ, я весь день был на работе).

Реальная проблема в том, что я не вижу, куда падает 2 . Одна вещь, о которой я думал, может быть проблемой (но я не знаю достаточно о Javascript, чтобы знать, возможно ли это):

Почта jQuery часто запускается; каждый раз, когда игрок вводит письмо. Возможно ли, что AnswerCorrect () может быть вызван несколько раз одновременно? Так что два или более «экземпляров» AnswerCorrect () работают одновременно?

РЕДАКТИРОВАТЬ 2

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

Ответы [ 2 ]

0 голосов
/ 29 июля 2011

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

Типичным случаем, когда в приложении с асинхронным вызовом ajax, подобным этому, и некоторым глобальным состоянием может быть что-то не так, является то, что асинхронная часть может быть выполнена неправильно. Он должен ждать обработчика успеха вызова сервера, прежде чем изменять какое-либо состояние. Если состояние изменено до того, как этот процесс будет обработан, то может закончиться с ошибкой.

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

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

EDIT:

Наиболее распространенная ошибка при первом использовании ajax-вызовов связана с асинхронной природой ajax-вызовов. Когда вы делаете вызов, он запускает ajax-вызов, и это происходит в фоновом режиме, в то время как остальная часть вашего кода продолжает работать. Он не заканчивается до тех пор, пока не будет вызвана функция завершения / успеха. Если вы забудете этот факт и сделаете другие вещи после того, как вы начали вызов ajax ДО того, как он завершится, тогда ваша логика будет неправильной. В примере, который вы разместили здесь, такой проблемы нет, но я полагаю, что после POST-запроса к серверу в вашем реальном коде есть что-то большее, и, возможно, это является источником ошибки / путаницы. Поскольку вы используете некоторые глобальные переменные для отслеживания состояния, если вы дотронетесь до любой из этих глобальных переменных после вызова POST и до вызова функции завершения (например, для перехода к следующему вопросу), это испортит вашу логику. Функция успеха будет выполнена, и ваше глобальное состояние будет неправильно изменено. Это всего лишь предположение, потому что все, что мне нужно, - это опубликованный вами код, в котором нет проблемы, с которой вы столкнулись.

Если вы хотите опубликовать реальный код или дать нам ссылку на реальную страницу, мы можем посмотреть там.

0 голосов
/ 29 июля 2011

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

Вы хотите, чтобы первый элемент находился вне массива, и вы хотите, чтобы длина массива изменялась соответствующим образом. Для этого вы должны использовать Array.prototype.shift(). Я переставил часть вашего кода для лучшей практики, но попытался оставить его в том же макете, чтобы не допустить его неузнаваемости:

var remaining = [ 1, 2, 3, 4, 5 ];

$( function()
{
    $( '#in' ).keyup( function()
    {
        // Send answer to server to check if it's right.
        CheckGuess( $( this ).val() );  
    } );

    Next();
} );

function CheckGuess( guess )
{
    if( guess.length > 2 && guess.length < 100 )
    {
        $.post( 
            'class/check.php',
            {
                current: + current,
                answer + guess
            },
            function( check )
            {
                if( check == 1 )
                {
                    Next();
                }
            },
            'json'
        );
    }   
}

function Next()
{
    // User guessed correctly.
    if( remaining.length )
    {
        current = remaining.shift();

        // Scroll to next question.
        $.scrollTo( $( '#m' + current ), { duration: 1000 } );

        // Clear input box.
        $( '#in' ).val( '' );
    }
    else
    {
        // Quiz complete.
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...