这是我的第一个问题,我希望我没有做错任何事。首先,谢谢你的阅读。
我的问题是...... 设计是使用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.
暂时,我必须每次都要提醒文本文件,这不是解决问题的好方法。
我的问题是,通过上述设计,有没有更好的方法来实现它而不必处理这个bug?
以下是演示:html和text。
非常感谢。
答案 0 :(得分: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>
答案 1 :(得分:0)
由于AJAX调用是异步的,因此在编辑函数返回后执行...因为听起来您通过一系列函数传递数据,我建议使用promise库(例如Q.js) 。这是一个使用Q.js演示的简单jsfiddle。
您的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;
}
上面,我还使用全局变量(test)来检索从异步调用中检索的数据。我在决定是否需要进行异步调用以获取值时检查此值,或者使用已从原始异步调用填充的值。使用最符合您需求的模式。
我还建议使用一个库进行异步调用,因为你的项目可能会因为执行原始AJAX调用而变得混乱。