# Ajax
# Ajax
2005年Jesse James Gayarrett发表了一篇文章,提到了一种新技术:Ajax
,是Asynchronous JavaScript + XML的简写,这一技术能够向服务器请求额外的数据而无需卸载页面,带来更好的用户体验。
Ajax技术的核心是XMLHttpRequest对象(XHR)
# XMLHttpRequest对象
创建xhr对象
const xhr = new XMLHttpRequest();
在使用XHR对象时,要调用的第一个方法就是open(),它接受三个参数:
- 发送的请求的类型
- 请求的URL
- 表示是否异步发送请求的布尔值
xhr.open('get', 'www.baidu.com', false);
open()方法并不会真正发送请求,而只是启动一个请求以备发送
只能向同一个域中使用相同端口或者协议的URL发送请求
要发送特定的请求,需要调用send()方法
xhr.open('get','www.baidu.com',false);
xhr.send();
同步请求 send()方法接受一个参数,即要作为请求主体发送的数据,如果不需要通过发送请求主体发送数据,则必须传入null,调用send()之后,请求就会被分派到服务器,由于设置第三个参数是false,表示是同步请求,JavaScript代码会等到服务器响应之后再继续执行。再收到响应后,响应的数据会自动的填充XHR对象的属性,属性包括:
- responseText: 作为响应主体被返回的文本
- responseXML: 如果响应的格式'text/xml'或者'application/xml',这个属性中将保存包含着响应数据的XML DOM文档
- status: 响应的HTTP状态
- statusText: HTTP状态的说明
异步请求 send()请求的第三个参数是true,表示是异步请求。此时,可以检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段。这个属性可取的值如下:
- 0: 未初始化,尚未调用open()方法
- 1: 启动,已经调用open()方法,但是尚未调用send()方法
- 2: 发送,已经调用open()方法,但是尚未接受到响应
- 3: 接收,已经接受到部分响应数据
- 4: 完成,已经接收到全部的响应数据,而且已经可以在客户端使用了
只要readyState的属性值发生变化,都会触发一次readystatechange事件。可以利用这个事件来检测每次状态变化后readyState的值,通常我们只对readyState值为4的事件进行处理。
const xhr = new XMLHttpRequest();
xhr.open('get', 'http://localhost:8080/api/home-loan-calculator', true);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.responseText);
} else {
console.log('Request was failed:', xhr.status);
}
}
};
xhr.setRequestHeader("X-Transaction-Id","123")
xhr.send(null);
console.log(xhr);
在接收到响应之前还可以调用abort()方法来取消异步请求:
xhr.abort()
调用这个方法后,XHR对象会停止触发事件,而且也不在允许访问任何与响应相关的对象属性。
# XMLHttpRequest 2级
XMLHttpRequest 1级只是把已有的XHR对象的实现细节描述了出来,而XMLHttpRequest 2级则进一步的发展了XHR。
# FormData
FormData为序列化表单以及创建与表单格式相同的数据提供了便利
var data = new FormData();
data.append("name", "sialvsic");
通过向FormData构造函数中传入表单元素,也可以用表单元素的数据预先向其中填入键值对
var data = new FormData(document.forms[0]);
创建了FormData的实例后,可以直接传入到send()方法中,FormData的便利之处就是不必明确的在XHR对象上设置请求头部。XHR对象能够识别出来传入的是FormData的实例,并自动的配置相应的头部信息。
# 超时设定
为XHR对象添加了一个timeout属性,表示请求在等待响应多少毫秒之后就终止。请求终止会调用ontimeout事件处理程序。
# 进度事件
一般地,使用readystatechange事件探测HTTP请求的完成。XHR2规范草案定义了进度事件Progress Events规范,XMLHttpRequest对象在请求的不同阶段触发不同类型的事件,所以它不再需要检査readyState属性。这个草案定义了与客户端服务器通信有关的事件。这些事件最早其实只针对XHR操作,但目前也被其他API(如File API)借鉴。
有以下6个进度事件:
- loadstart: 在接收到响应数据的第一个字节时触发
- progress: 在接收响应期间持续不断地触
- error: 在请求发生错误时触发
- abort: 在因为调用abort()方法而终止连接时触发
- load: 在接收到完整的响应数据时触发
- loadend: 在通信完成或者触发error、abort或load事件后触发
- timeout: 超时发生时触发
# load事件
Firefox在实现XHR对象的某个版本时,曾致力于简化异步交互模型。最终,Firefox实现中引入了load事件,用以替代readystatechange事件。响应接收完毕后将触发Load事件,因此也就没有必要去检查readyState属性了。而onload事件处理程序会接收到一个event对象,其target属性就指向XHR对象实例,因而可以访问到XHR对象的所有方法和属性。然而,并非所有浏览器都为这个事件实现了适当的事件对象。结果,开发人员还是要像下面这样被迫使用XHR对象变量。
const xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.baidu.com', false);
xhr.onload = function(event){
console.log(event)
};
xhr.open('get', 'example.php', true);
xhr.send(null);
# progress事件
progress事件会在浏览器接收新数据期间周期性地触发。而onprogress事件处理程序会接收到一个event对象,其target属性是XHR对象,但包含着三个额外的属性:lengthComputable、loaded和total。其中,lengthComputable是一个表示进度信息是否可用的布尔值,loaded表示已经接收的字节数,loaded表示根据Content-Length响应头部确定的预期字节数。有了这些信息,我们就可以为用户创建一个进度指示器了
var xhr = createXHR();
xhr.onload = function () {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
};
//get请求一般用来获取下载进度
xhr.onprogress = function (event) {
var divStatus = document.getElementById("status");
if (event.lengthComputable) {
divStatus.innerHTML = "Recived" + event.loaded + " of " + event.total + " bytes";
}
}
xhr.open("get", "altevents.php", true);
xhr.send(null);
为确保正常执行,必须在调用open()方法之前添加onprogress事件处理程序。在前面的例子中,每次触发progress事件,都会以新的状态信息更新HTML元素的内容。如果响应头部中包含Content-Length字段,那么也可以利用此信息来计算从响应中已经接收到的数据的百分比。
当请求类型为post时需要监听xhr.upload
//post一般用来获取上传进度
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
console.log(e.loaded / e.total * 100)
}
}