Значение глобальной переменной JavaScript не изменяется до тех пор, пока не появится предупреждение

0

Это мой первый вопрос, и я надеюсь, что я не сделаю ничего плохого. Прежде всего, спасибо за чтение.

И моя проблема...
Дизайн состоит в том, чтобы прочитать некоторые данные в текстовом файле с помощью JavaScript, обработать их через ряд функций, прежде чем создавать контент для отображения в HTML-div. После некоторого поиска я понял, что это можно сделать с помощью XMLHttpRequest. Поскольку прочитанные данные будут обработаны некоторыми функциями, я решил сохранить их в глобальной переменной для легкого доступа. Сначала код работал нормально, и я смог распечатать полученные данные в div. Но потом я заметил странную ошибку. Если я передам эти данные глобальной переменной и попытаюсь получить их позже, я получу первоначально назначенное значение или не определено. Я пытаюсь предупредить, что значение глобальной переменной, и я вижу, что я получаю выше. Однако, если я еще раз предупрежу, значение изменится на то, что мне нужно. Я только что изучил JavaScipt на короткое время, столкнувшись с этой ошибкой, я полностью потерял меня.

Файл html:

<html>

<head>
    <meta charset="UTF-8">
    <title>Read file</title>

<script>
var output = ["next"];

function edit()
{
    var rawFile = new XMLHttpRequest();
    rawFile.open("GET", "test.txt", true);
    rawFile.responseType = "text";
    rawFile.onreadystatechange = function ()
    {
        if(rawFile.readyState === 4)
        {
            if(rawFile.status === 200 || rawFile.status == 0)
            {
                output[0] = rawFile.responseText;
                //alert("Reading okay!");
            }
        }
    };
    rawFile.send(null);
    console.log(output[0]); // initial value
    alert(output[0]); // initial value
    console.log(output[0]);  // desired value
    alert(output[0]);  // desired value
}
</script>
</head>

<body>
    <button onclick="edit()">Read test.txt</button>
</body>

</html>

Текстовый файл:

This is the content of the text file.

Временно, я должен предупреждать каждый раз, когда текстовый файл читается, что не является хорошей идеей для решения проблемы.
Мой вопрос в том, что с вышеупомянутым дизайном есть ли лучший способ его реализовать, не имея дело с этой ошибкой?
И вот демо: html и текст.

Большое спасибо.

  • 0
    это потому, что вы пытаетесь получить данные сразу, по умолчанию вызовы xhr являются асинхронными, то есть они выполняются, пока ваш код продолжается, вам нужно либо перехватить onreadystatechange, либо изменить вызов на синхронизирующий.
  • 1
    См. Stackoverflow.com/questions/14220321/…
Показать ещё 1 комментарий
Теги:

2 ответа

0
Лучший ответ

Поскольку вызов AJAX асинхронен, он выполняется после того, как функция редактирования возвращается... Так как кажется, что вы передаете свои данные с помощью ряда функций, я предлагаю использовать библиотеку обещаний (например, Q.js). Вот простой jsfiddle, который демонстрирует использование Q.js.

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

//Global variable for test.txt
var test;

function edit()
{
    /*
    var deferred = Q.defer();
    var rawFile = new XMLHttpRequest();
    rawFile.open("GET", "test.txt", true);
    rawFile.responseType = "text";
    rawFile.onreadystatechange = function ()
    {
        if(rawFile.readyState === 4)
        {
            if(rawFile.status === 200 || rawFile.status == 0)
            {
                //resolve promise with responseText;
                deferred.resolve(rawFile.responseText);
            }
        }
    };
    deferred.promise
        .then(processStep1)
        .then(processStep2)
        .then(processStep3);
    */

    //Imitating async call that will finish after 2 seconds
    var deferred;
    var promise;
    //if we haven't read the file yet, then make async call
    if (test === undefined) {
        deferred = Q.defer();

        setTimeout(function () {
            test = "This is the content of the text file."
            deferred.resolve(test);
        }, 2000);

        promise = deferred.promise;
    }
    //Else we've already read the file. 
    else {
        promise = Q(test);
    }

    //Start adding your functions to process text here:
    promise.then(processStep1)
        .then(processStep2)
        .then(processStep3);
}

function processStep1(data) {
    alert("Step 1: " + data);
    //adding some stuff onto data for example
    data = data + "... And more data.";
    return data;
}

function processStep2(data) {
    alert("Step 2: " + data);
    data = "Adding data to front. " + data;
    return data;
}

function processStep3(data) {
    alert("Step 3: " + data);
    return data;
}

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

Я также рекомендовал бы библиотеку для выполнения асинхронных вызовов, так как ваш проект может быстро запутаться, выполняя необработанные вызовы AJAX.

  • 0
    Большое спасибо. Ваше объяснение и демонстрация очень ценятся. Я изучу библиотеку обещаний, которую вы предложили, чтобы найти решение, наиболее подходящее моему случаю. Перед тем, как начать, я думал, что JavaScript - это просто, не зная, что есть jQuery и AJAX для изучения. Вся картина огромна.
1

Это потому, что значение изменяется асинхронно.

Предупреждение не является гарантией, это просто задержка, после которой может быть выполнен обратный вызов AJAX или нет.

Если вы хотите использовать нужное значение, вы должны запустить свой код в onreadystatechange.


Пример:

function edit(callback)
{
    /* ... */
    rawFile.onreadystatechange = function () {
        if(rawFile.readyState === 4 && (rawFile.status === 200 || rawFile.status == 0)) {
            output[0] = rawFile.responseText;
            //alert("Reading okay!");
            callback();
        }
    };
    /* ... */
}
fuunction afterEdit(){
    alert(output[0]);  // desired value
}

<button onclick="edit(afterEdit)">Read test.txt</button>
  • 0
    Почему отрицательный голос?
  • 0
    Спасибо, что ответили. Ваше решение тоже работает.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню