Это мой первый вопрос, и я надеюсь, что я не сделаю ничего плохого. Прежде всего, спасибо за чтение.
И моя проблема...
Дизайн состоит в том, чтобы прочитать некоторые данные в текстовом файле с помощью 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 и текст.
Большое спасибо.
Поскольку вызов 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.
Это потому, что значение изменяется асинхронно.
Предупреждение не является гарантией, это просто задержка, после которой может быть выполнен обратный вызов 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>