我正在阅读“学习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在第二个中未定义?任何帮助是极大的赞赏。
答案 0 :(得分:0)
您的两个问题的答案都在于异步的本质。如果async
为true
,则返回null
:
xhttp.open("GET",dname,false);
xhttp.send();
return xhttp.responseXML;
...因为在return
语句发生时HTTP请求尚未完成,因此xhttp.responseXML
仍然具有其默认值(null
)。 HTTP请求稍后在该代码流之外完成(异步 - 字面上,不同步)。
您的getResponse
函数根本不会返回任何值。您已分配给onreadystatechange
的匿名回调函数会返回一个值,但这不会影响getResponse
的返回值。
客户端Web编程的一个关键方面是采用环境的异步,事件驱动的特性。几乎没有用于在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的牺牲品。强烈建议声明所有变量,并将所有代码包装在作用域函数中以避免创建全局符号(浏览器上的全局命名空间已经过度拥挤)。
答案 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
})