我正在“学习 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 在第二个示例中未定义?任何帮助是极大的赞赏。
最佳答案
这两个问题的答案在于异步 的本质。当 async
为 true
时,这将返回 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
});
请注意我是如何将所有依赖于响应的代码移动到一个函数中,然后将该函数传递给 getResponse
。 getResponse
在有数据时调用它。请求/响应、事件驱动、异步,无论你想怎么调用它,这是尽早采用的关键。 :-)
旁注:您的代码正在成为 The Horror of Implicit Globals 的牺牲品.强烈建议声明所有变量,并将所有代码包装在作用域函数中以避免创建全局符号(浏览器上的全局命名空间已经人满为患)。
关于Javascript TypeError 变量未定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13658757/