Javascript TypeError 变量未定义

标签 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。所以我的第一个问题是,为什么 async 必须为 false 才能返回 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”。在异步设置为 true 或 false 的函数 getResponse() 中它不起作用,我得到 xmlDoc is undefined 错误。在设置为 loadXMLDoc() 的返回之前,xmlDoc 未在第一个示例(来自 w3schools.com)的其他地方定义,并且工作正常。 ajaxRequest() 是书外的,getResponse() 中的大部分内容都是书外的,但我把它放在 getResponse() 函数中。从这个脚本调用时,processapi.php 只是回显一个 XML 文档。

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

最佳答案

这两个问题的答案在于异步 的本质。当 asynctrue 时,这将返回 null:

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

...因为 return 语句发生时 HTTP 请求尚未完成,所以 xhttp.responseXML 仍然具有其默认值()。 HTTP 请求稍后完成,脱离了该代码流(异步——从字面上看,不是同步的)。

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

客户端网络编程的一个关键方面是拥抱环境的异步、事件驱动的特性。在 XHR 请求中,几乎没有将 async 设置为 false 的用例。相反,习惯于对事物使用回调。例如,您的 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 的牺牲品.强烈建议声明所有变量,并将所有代码包装在作用域函数中以避免创建全局符号(浏览器上的全局命名空间已经人满为患)。

关于Javascript TypeError 变量未定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13658757/

相关文章:

javascript - 与 apollo-server 的 Websocket 连接返回乱码的 connectionParams

javascript - Angular 4 到 Angular 5 找不到模块 '@angular/router'

javascript - 每个表行的 ASP.NET MVC ADO.NET 查询

java - Spring MVC + JQuery + Ajax 问题

ruby-on-rails - 带有 Remotipart 的 Rails AJAX 上传表单

javascript - 删除 div 内的一行

javascript - 异步等待返回未定义的javascript

javascript - 使用 webpack 的 require.ensure 函数为 javascript 模块编写测试

javascript - 我的 displayError() 函数根本不起作用

javascript - 在 jQuery AJAX 的 foreach 循环中排除某些对象属性