AJAX是Asynchronous JavasSript And XML的简写,这项技术能够在不卸载页面的情况下发出HTTP请求,虽然名字中包含XML,但AJAX通信与数据格式无关
AJAX通信通常包含4个步骤:
- 创建XMLHttpRequest对象
- 发送HTTP请求
- 接收服务器返回的数据
- 更新网页数据
创建
AJAX技术的核心是XMLHttpRequest对象(简称XHR),可以直接使用new关键字实例化一个XHR对象
var xhr = new XMLHttpRequest()
注意: 如果要建立N个不同的请求,理论上需要使用N个不同的XHR对象。如果重用已存在的XHR对象,会终止之前通过该对象挂起的任何请求
发送请求
open()
XHR对象的open()方法用于发送请求,该方法接收三个参数:请求方式、请求地址和一个布尔值
xhr.open("GET","/api/test", true);
请求方式:请求方式比较常用的是GET和POST,也可以是PATCH、DELETE、OPTIONS等。这个字符串是不区分大小写的,但通常使用大写字母。
请求地址:请求地址通常是相对于执行代码的当前页面。如果需要发出跨域请求,后端要支持CORS,否则会报错
布尔值:布尔值表示是否异步发送请求的布尔值,默认为true,表示异步发送
其他:如果请求一个受密码保护的URL,可以把用于认证的用户名和密码作为第4和第5个参数传递给open()方法
send()
open()方法调用后,必须执行send()方法才会真正发送请求。如果是GET方式,send()方法无参数,或参数为null;如果是POST方式,send()方法的参数为要发送的数据
xhr.open('GET', 'https://www.86886.wang/api/tags', true);
xhr.send(null);
接收响应
一个完整的HTTP请求由响应状态码、响应头集合和响应主体组成。在收到响应后,这些都可以通过XHR对象的属性和方法使用,主要有以下4个属性
responseText: 作为响应主体被返回的文本(文本形式)
responseXML: 如果响应的内容类型是'text/xml'或'application/xml',这个属性中将保存着响应数据的XML DOM文档(document形式)
status: HTTP状态码(数字形式),比如200
statusText: HTTP状态说明(文本形式),比如OK
在接收到响应后,第一步是检测status状态,HTTP状态码为200表示请求成功,此时responseText属性的内容已经就绪。另外状态码304表示资源没有被修改,可以直接从浏览器缓存获取,这个响应也是有效的
无论内容类型是什么,响应主体的内容都会保存到responseText属性中。对于非XML数据而言(如JSON),responseXML属性的值将为null
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
}else{
console.log('Request fail:' + xhr.status);
}
同步请求
把open()方法的第三个参数设置为false,表示是同步请求,此时send()方法将会阻塞直到请求完成。由于JS是单线程的,所以会导致整个浏览器UI冻结,如果连接的服务器响应慢,那么用户的浏览器将冻结
开发中要避免使用同步请求,下面是同步请求的示例
<div id="result"></div>
<button id="btn">GET同步请求</button>
<script>
btn.onclick = function() {
var data = ajax();
result.innerHTML = data;
}
function ajax() {
var xhr = new XMLHttpRequest();
if(xhr.readyState == 4) {
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
return xhr.responseText;
}
}
// 同步请求
xhr.open('GET', 'https://www.86886.wang/api/tags', false);
xhr.send();
}
</script>
异步请求
异步请求需要检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段,取值如下:
0(UNSENT):未初始化。尚未调用open()方法
1(OPENED):启动。已经调用open()方法,但尚未调用send()方法
2(HEADERS_RECEIVED):发送。己经调用send()方法,且接收到头信息
3(LOADING):接收。已经接收到部分响应主体信息
4(DONE):完成。已经接收到全部响应数据,而且已经可以在客户端使用了
只要readyState属性值发生变化,就会触发onreadystatechange事件,通常只需要对值为4时做判断,此时表示数据已经准备就绪
注意: 必须在调用open()之前指定onreadystatechange 事件处理程序才能确保跨浏览器兼容性,否则将无法接收readyState属性为0和1的情况
异步请求示例
<div id="result"></div>
<button id="btn">GET异步请求</button>
<script>
btn.onclick = function() {
ajax(function(data) {
result.innerHTML = data;
});
}
function ajax(cb) {
var xhr = new XMLHttpRequest();
// 异步请求
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
cb(xhr.responseText);
}
}
}
xhr.open('GET', 'https://www.86886.wang/api/tags', true);
xhr.send();
}
</script>
超时
XHR对象有一个timeout属性,表示多少毫秒后,如果请求仍然没有得到结果就会自动终止。默认值0,表示没有限制
如果请求超时,会触发ontimeout事件
function ajax(cb) {
var xhr = new XMLHttpRequest();
// 异步请求
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
cb(xhr.responseText);
}
}
}
xhr.open('GET', 'https://www.86886.wang/api/tags', true);
xhr.ontimeout = function() {
console.log('The request timed out.');
}
xhr.timeout = 5000; // 5s
xhr.send();
}