Javascript TypeError变量未定义

时间:2012-12-01 11:01:15

标签: javascript ajax

我正在阅读“学习PHP,MySQL和JavaScript -O'Reilly”中的一些非常基本的AJAX编程。有一些非常基本的程序,Java使用AJAX获取一些文本或页面。我正在使用W3Schools.com网站尝试了解有关使用AJAX获取XML格式文档的更多信息。我有两个与我正在学习的问题有关的问题。

当我使用http://www.w3schools.com/dom/dom_loadxmldoc.asp中的代码时,我可以使用下面的代码段返回XML文档:

function loadXMLDoc(dname)
{
if (window.XMLHttpRequest)
  {
  xhttp=new XMLHttpRequest();
  }
else
  {
  xhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
xhttp.open("GET",dname,false);
xhttp.send();
return xhttp.responseXML;
}

//called this way
xmlDoc=loadXMLDoc("books.xml");

但是必须将async设置为false才能使其正常工作。如果我将async设置为true,则返回null。所以我的第一个问题是为什么必须异步才能返回XML文档?

我的第二个问题,当我尝试合并本书中的一些代码和网站上的一些代码时,代码段如下:

<body>API Call output
<div id='output'>will be here</div>
<script>
out = ""
xmlDoc = getResponse()
users = xmlDoc.getElementsByTagName('username')
for (count = 0; count < users.length ; count++)
{
    out += "Username: " + users[count].childNodes[0].nodeValue + '<br />'
}
document.getElementById('output').innerHTML = out

function ajaxRequest()
{
    try //good browser
    {
        var request = new XMLHttpRequest()
    }
    catch(e1)
    {
        try // IE6+
        {
            request = new ActiveXObject("Msxml2.XMLHTTP")
        }
        catch(e2)
        {
            request = false
        }
    }//end catch(e1)
    return request
}

function getResponse()
{
    params = "apikey=test"
    request = new ajaxRequest()
    request.open("POST", "processapi.php", true)
    request.setRequestHeader("Content-type",
        "application/x-www-form-urlencoded")
    request.setRequestHeader("Content-length", params.length)
    request.setRequestHeader("Connection", "close")
    request.onreadystatechange = function()
    {
        if (this.readyState == 4)
        {
            if (this.status == 200)
            {
                if (this.responseXML != null)
                {
                    return this.responseXML
                }
                else alert("Ajax error: No data received")
            }
            else alert( "Ajax error: " + this.statusText)
        }
    }

    request.send(params)
}
</script>
</body>

我收到错误“TypeError:xmlDoc is undefined”。在函数getResponse()中,async设置为true或false,它不起作用,我得到xmlDoc是未定义的错误。在设置为loadXMLDoc()的返回之前,xmlDoc在第一个示例(来自w3schools.com)的其他地方没有定义,并且可以正常工作。 ajaxRequest()不在书中,并且getResponse()中的大多数内容都不在书中,但我把它放在了getResponse()函数中。 processapi.php只是在从这个脚本调用时回显一个XML文档。

为什么异步在第一个示例中不起作用,为什么xmlDoc在第二个中未定义?任何帮助是极大的赞赏。

2 个答案:

答案 0 :(得分:0)

您的两个问题的答案都在于异步的本质。如果asynctrue,则返回null

xhttp.open("GET",dname,false);
xhttp.send();
return xhttp.responseXML;

...因为在return语句发生时HTTP请求尚未完成,因此xhttp.responseXML仍然具有其默认值(null)。 HTTP请求稍后在该代码流之外完成(异步 - 字面上,不同步)。

您的getResponse函数根本不会返回任何值。您已分配给onreadystatechange的匿名回调函数会返回一个值,但这不会影响getResponse的返回值。

客户端Web编程的一个关键方面是采用环境的异步,事件驱动的特性。几乎没有用于在XHR请求上设置asyncfalse的用例。相反,习惯于使用回调。例如,您的getResponse函数可能如下所示:

// ***CHANGE*** -----v--- Accept a callback
function getResponse(callback)
{
    params = "apikey=test"
    request = new ajaxRequest()
    request.open("POST", "processapi.php", true)
    request.setRequestHeader("Content-type",
        "application/x-www-form-urlencoded")
    request.setRequestHeader("Content-length", params.length)
    request.setRequestHeader("Connection", "close")
    request.onreadystatechange = function()
    {
        if (this.readyState == 4)
        {
            if (this.status == 200)
            {
                if (this.responseXML != null)
                {
                    // ***CHANGE*** Trigger the callback with the response
                    callback(this.responseXML);
                }
                else alert("Ajax error: No data received")
            }
            else alert( "Ajax error: " + this.statusText)
        }
    }

    request.send(params)
}

然后,而不是这个:

out = ""
xmlDoc = getResponse()
users = xmlDoc.getElementsByTagName('username')
for (count = 0; count < users.length ; count++)
{
    out += "Username: " + users[count].childNodes[0].nodeValue + '<br />'
}
document.getElementById('output').innerHTML = out
你会这样做:

getResponse(function(xmlDoc) {
    out = ""
    users = xmlDoc.getElementsByTagName('username')
    for (count = 0; count < users.length ; count++)
    {
        out += "Username: " + users[count].childNodes[0].nodeValue + '<br />'
    }
    document.getElementById('output').innerHTML = out
});

请注意我是如何将依赖响应的所有代码移动到函数中,然后将该函数传递给getResponsegetResponse在拥有数据时调用它。请求/响应,事件驱动,异步,无论你想要什么,这是一个早期关键的事情。 : - )


旁注:您的代码正在成为The Horror of Implicit Globals的牺牲品。强烈建议声明所有变量,并将所有代码包装在作用域函数中以避免创建全局符号(浏览器上的全局命名空间已经过度拥挤)。

答案 1 :(得分:0)

getResponse正在执行异步XHR请求,因此函数将在结果准备好之前返回。您需要使用回调方法,

更改函数声明以接受回调参数:

function getResponse(callback) {

然后在函数体中修改此部分

if (this.responseXML != null)
{
    return this.responseXML; // WRONG
}

以便在收到XML

时调用回调
if (this.responseXML != null)
{
    callback(this.responseXML); // GOOD
}

然后你会像这样打电话给getResponse

getResponse(function(xmlDoc){
   // do something with xmlDoc
})