JavaScript全局变量值在发出警报后才会更改

时间:2014-04-07 16:36:18

标签: javascript html

这是我的第一个问题,我希望我没有做错任何事。首先,谢谢你的阅读。

我的问题是...... 设计是使用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? 以下是演示:htmltext

非常感谢。

2 个答案:

答案 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调用而变得混乱。