<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Example</title></head><body><div><button>apples</button><button>cherries</button><button>bananas</button></div><div id="target">Press a button</div><script type="application/javascript"> var buttons = document.getElementsByTagName("button");for(var i=0; i<buttons.length; i++){buttons[i].onclick = handleButtonPress;}//脚本会调用此函数以响应 button 控件的 click 事件function handleButtonPress(e){//创建一个新的 XMLHttpRequest 对象var httpRequest = new XMLHttpRequest();//给 onreadystatechange 事件设置一个事件处理器httpRequest.onreadystatechange = handleResponse;//使用 open 方法来指定 HTTP 方法和需要请求的 URL (即告诉 httpRequest 对象你想要做的事)httpRequest.open("GET", e.target.innerHTML+".html");//这里没有向服务器发送任何数据,所以 send 方法无参数可用httpRequest.send();}//处理响应//一旦脚本调用了 send 方法,浏览器就会在后台发送请求到服务器。因为请求是在后台处理的,所以Ajax 依靠事件来通知这个请求的进展情况。function handleResponse(e){//当 onreadystatechange 事件被触发后,浏览器会把一个 Event 对象传递给指定的处理函数,target 属性则会被设为与此事件关联的XMLHttpRequestif(e.target.readyState == XMLHttpRequest.DONE && e.target.status == 200){ //请求成功document.getElementById("target").innerHTML = e.target.responseText; //显示被请求文档的内容}}</script></body></html>三个额外的文档非常简单:<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Apples</title><style>img { float:left;padding:2px;margin:5px;border: medium double black;background-color: lightgrey; width: 100px;height: 100px;}</style></head><body><p><img src="../img/show-page/img_apples.jpg"/>Page for apples.</p></body></html>效果如下图所示:
随着用户点击各个水果按钮,浏览器会异步执行并取回所请求的文档,而主文档不会被重新加载。这就是典型的 Ajax 行为。
2. 使用 Ajax 事件
建立和探索一个简单的示例之后,可以开始深入了解 XMLHttpRequest 对象支持的功能,以及如何在请求中使用它们了。起点就是第二级规范里定义的那些额外事件:

这些事件大多数会在请求的某一特定时间点上触发。 readystatechange 和 progress 这两个事件是例外,它们可以多次触发以提供进度更新。
调度这些事件时,浏览器会对 readystatechange 事件使用常规的 Event 对象,对其他事件则使用 ProgressEvent 对象。 ProgressEvent 对象定义了 Event 对象的所有成员,并增加了下图中介绍的这些成员:

下面代码展示了如何使用这些事件:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Example</title><style>table {margin: 10px;border-collapse: collapse; float: left;}div{margin: 10px;}td,th{padding: 4px;}</style></head><body><div><button>apples</button><button>cherries</button><button>bananas</button></div><table id="events" border="1"></table><div id="target">Press a button</div><script type="application/javascript">var buttons = document.getElementsByTagName("button");for(var i=0; i<buttons.length; i++){buttons[i].onclick = handleButtonPress;}var httpRequest;function handleButtonPress(e){clearEventDetails();httpRequest = new XMLHttpRequest();httpRequest.onreadystatechange = handleResponse;httpRequest.onerror = handleError;httpRequest.onload = handleLoad;;httpRequest.onloadend = handleLoadEnd;httpRequest.onloadstart = handleLoadStart;;httpRequest.onprogress = handleProgress;httpRequest.open("GET", e.target.innerHTML+".html");httpRequest.send();}function handleResponse(e){displayEventDetails("readystate("+httpRequest.readyState+")")if(e.target.readyState == XMLHttpRequest.DONE && e.target.status == 200){document.getElementById("target").innerHTML = e.target.responseText;}}function handleError(e){ displayEventDetails("error",e);}function handleLoad(e){ displayEventDetails("load",e);}function handleLoadEnd(e){ displayEventDetails("loadend",e);}function handleLoadStart(e){ displayEventDetails("loadstart",e);}function handleProgress(e){ displayEventDetails("progress",e);}function clearEventDetails(){document.getElementById("events").innerHTML = "<tr><th>Event</th><th>lengthComputable</th><th>loaded</th><th>total</th>";}function displayEventDetails(eventName,e){if(e){document.getElementById("events").innerHTML+="<tr><td>"+eventName+"</td><td>"+ e.lengthComputable+"</td><td>"+ e.loaded+"</td><td>"+ e.total+"</td></tr>";}else {document.getElementById("events").innerHTML += "<tr><td>"+eventName+"</td><td>NA</td><td>NA</td><td>NA</td></tr>";}}</script></body></html>这是之前示例的一种变型,为一些事件注册了处理函数,并在一个 table 元素里为处理的每个事件都创建了一条记录。从下图中可以看到 Firefox 浏览器是如何触发这些事件的。
try{...httpRequest.open("GET","http://")...httpRequest.send();}catch(error){displayErrorMsg("try/catch",error.message)} catch 子句让你有机会从错误中恢复。可以选择提示用户输入一个值,也可以回退至默认的URL ,或是简单地丢弃这个请求。 在这个例子中,仅仅调用了 displayErrorMsg 函数来显示错误消息。httpRequest.open("GET",http://www.ycdoitt.com/nopage.html)这个URL 存在两个问题。第一个问题是主机名不能被 DNS 解析,因此浏览器无法生成服务器连接。这个问题知道 XMLHttpRequest 对象开始生成请求时才会变得明显,因此它会以两种方式发出错误信号。如果你注册了一个 error 事件的监听器,浏览器就会向你的监听函数发送一个 Event 对象。以下是示例中使用的函数:
function handleError(e){displayErrorMsg("Error event",httpRequest.status + httpRequest.statusText);} 当这类错误发生时,能从 XMLHttpRequest 对象获得何种程度的信息取决于浏览器,遗憾的是大多数情况下,会得到的值为 0的 status和空白的 statusText 值。if(httpRequest.status == 200){target.innerHTML = httpRequest.responseText;}else{document.getElementById("statusmsg").innerHTML= "Status:" + httpRequest.status +" "+ httpRequest.statusText;}在这个例子中,只是简单的显示了status和statusText的值。而在真正的应用程序里,需要以一种有用且有意义的方式进行恢复(比如显示备用内容或警告用户有问题,具体看哪种更适合应用程序)。
httpRequest.open("GET","http://myserver/records/freeman/adam");这里只展示了HTTP方法和请求的URL。要使这个请求能顺利工作,服务器端必须由应用程序能理解这个请求,并将它转变成一段合适的数据以发送回服务器。如果想删除数据,可以这么写:
httpRequest.open("DELETE","http://myserver/records/freeman/adam");此处的关键在于通过HTTP方法表达出你想让服务器做什么,而不是把它用某种方式编码进URL。
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Example</title></head><body><div><button>apples</button><button>cherries</button><button>bananas</button></div><div id="target">Press a button</div><script>var buttons = document.getElementsByTagName("button");for(var i = 0; i < buttons.length; i++){buttons[i].onclick = handleButtonPress;}var httpRequest;function handleButtonPress(e){httpRequest = new XMLHttpRequest();httpRequest.onreadystatechange = handleResponse;httpRequest.open("GET", e.target.innerHTML+".html");httpRequest.setRequestHeader("X-HTTP-Method-Override","DELETE");httpRequest.send();}function handleError(e){displayErrorMsg("Error event",httpRequest.status+httpRequest.statusText);}function handleResponse(){if(httpRequest.readyState == 4 && httpRequest.status == 200){document.getElementById("target").innerHTML = httpRequest.responseText;}}</script></body></html>在这个例子中,有使用XMLHttpRequest对象上的setRequestHeader方法来表明想让这个请求以HTTP DELETE方法的形式进行处理。请注意我在调用open方法之后才设置了这个标头。如果试图在open方法之前使用setRequestHeader方法,XMLHttpRequest对象就会抛出一个错误。httpRequest = new XMLHttpRequest();httpRequest.onreadystatechange = handleResponse;httpRequest.open("GET", e.target.innerHTML+".html");httpRequest.setRequestHeader("Cache-Control","no-cache");httpRequest.send();设置标头的方式和之前的例子一样,但这次用到的标头是 Cache-Control,而想要的值是 no-cache。放置这条语句后,如果通过Ajax请求的内容发生了改变,就会在下一次请求文档时体现出来。
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta content="width=device-width,user-scalable=no" name="viewport" /><meta name="author" content="叶超Luka" /><meta name="description" content="A simple example" /><title>Example</title><link href="../img/ycdoit.ico" type="image/x-icon" rel="shortcut icon" /><style>#allheaders,#ctheader{border: medium solid black;padding: 2px;margin: 2px;}</style></head><body><div><button>apples</button><button>cherries</button><button>bananas</button></div><div id="ctheader"></div><div id="allheaders"></div><div id="target">Press a button</div><script>var buttons = document.getElementsByTagName("button");for(var i = 0; i < buttons.length; i++){buttons[i].onclick = handleButtonPress;}var httpRequest;function handleButtonPress(e){httpRequest = new XMLHttpRequest();httpRequest.onreadystatechange = handleResponse;httpRequest.open("GET", e.target.innerHTML+".html");httpRequest.setRequestHeader("Cache-Control","no-cache");httpRequest.send();}function handleResponse(){if(httpRequest.readyState==2){document.getElementById("allheaders").innerHTML = httpRequest.getAllResponseHeaders();document.getElementById("ctheader").innerHTML = httpRequest.getResponseHeader("Content-Type");}else if(httpRequest.readyState == 4 && httpRequest.status == 200){document.getElementById("target").innerHTML = httpRequest.responseText;}}</script></body></html>效果图如下:
根据此图可以看出开发服务器正在运行的Web服务器软件是 IntelliJ IDEA 15.0.4,最后修改 apples.html 文档的时间是6月27日(但屏幕截图是7月5日)。