Ajax用一句话来说就是无须刷新页面即可从服务器取得数据(局部刷新)。注意,虽然Ajax翻译过来叫异步JavaScript与XML,但是获得的数据不一定是XML数据,现在服务器端返回的都是JSON格式的文件。
一、Ajax请求过程
完整的Ajax请求过程:
① 创建XHR实例 ( XMLHttpRequest 或 ActiveXObject )
② 发出HTTP请求(send()、open() )
③ 接收服务器传回的数据
④ 更新网页数据
注:异步Ajax请求中③要放②前,且需要用存储函数onreadystatechange,每当 readyState 属性改变时就会调用该函数,相当于一直监听服务器传回的数据 ;而同步的Ajax请求中②要放③前,因为是阻塞的,所以不用实时监听。
1、异步Ajax请求:
(1)用 GET请求的完整代码
// 创建XMLHttpRequest实例
var xhr;
if (window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");//IE6, IE5
}
//监听接收服务器传回的数据
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){ // 判断请求响应过程阶段,4 阶段代表已接收到数据
if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) { // 校验HTTP状态码
console.log(xhr.responseText); // 输出响应的文本
} else {
console.error(xhr.status, xhr.statusText); // 打印其他HTTP状态码
}
}
};
//发出HTTP请求
xhr.open('get', './example.txt', true); // 初始化xhr实例,或者说启动请求
//如果想在get中传点参数可以在url中添加
//xhr.open("get","example.php?name1=value1&name2=value2",true);
xhr.send(null); // 设置HTTP请求携带参数,null为不带参数
(2)用POST请求的完整代码
默认情况下,服务器对 POST请求
和 提交的Web表单
并不会一视同仁。因此服务器必须有程序来读取发送过来的原始数据并从中解析出有用部分。
我们可以使用XHR来模仿表单提交。首先将表单提交的内容类型content-type
头部信息设置为application/x-www-form-urlencoded
,其次是以适当的格式创建一个字符串。如果不设置content-Type头部信息,那么发送给服务器的数据就不会出现在$_POST这个全局变量中。
// 创建XMLHttpRequest实例
var xhr;
if (window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");//IE6, IE5
}
//监听接收服务器传回的数据
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){ // 判断请求响应过程阶段,4 阶段代表已接收到数据
if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) { // 校验HTTP状态码
console.log(xhr.responseText); // 输出响应的文本
} else {
console.error(xhr.status, xhr.statusText); // 打印其他HTTP状态码
}
}
};
//发出HTTP请求
//如果你用POST传递非表单数据
var data = "username=" + username + "&password=" + password;
xhr.open('post', 'example.txt', true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(data);
//如果你用POST传递表单数据,则要将表单数据序列化
//其实还有更简单的方法,直接用XHR2的FromData对象,下面会讲解
//xhr.open('post', 'example.txt', true);
//xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//var form = document.getElementById('myform');
//xhr.send(serialize(form)); //将表单数据序列化
2、同步Ajax请求:
// 创建XMLHttpRequest实例
var xhr;
if (window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");//IE6, IE5
}
//发出HTTP请求
xhr.open('get', 'http://www.baidu.com', false)
xhr.send(null)
// 接收服务器传回的数据
if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) { // 校验HTTP状态码
console.log(xhr.responseText); // 输出响应的文本
} else {
console.error(xhr.status, xhr.statusText); // 打印其他HTTP状态码
}
二、Ajax请求过程详解
1、 创建XHR实例
如果是普通浏览器则创建XMLHttpRequest;如果是IE浏览器则创建ActiveXObject对象。
var xhr;
if (window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");//IE6, IE5
}
2、 发出HTTP请求
(1)open():启动请求
实例创建好后,首先需要启动一个HTTP请求
,用XHR的open()
方法实现;调用open()方法后会启动一个http请求,但它不会立即发送请求,而是处于待命状态。
//eg:
xhr.open('get', 'http://www.baidu.com', true)
//带参数的get请求
xhr.open("get","example.php?name1=value1&name2=value2",true);
open方法接受三个参数:
① 参数一:http请求使用方法,如(’get’,’post’等)
② 参数二:请求的url,
③ 参数三:是否异步发送请求(可选)
注:
请求的url
必须要跟请求
都满足同源策略
,也就是说协议、域名、端口号要一致;若要跨域请求则要使用别的方法。
(2)send():发送请求
接着调用send()方法就会发出这个http请求。
send()方法接受一个参数,为http请求发送的数据(通常用于’post’方法),如果为null,表示不发送数据。
xhr.open('get', 'http://www.baidu.com', true);
xhr.send(null);// 设置HTTP请求携带参数,null为不带参数
至此,一个异步的http请求就发送到了服务器。
3、接收服务器传回的数据
XHR对象的属性:
- responseText:作为响应主体被返回的文本。
- responseXML: 响应返回的XML文档,能接收到的前提是,响应的Content-Type字段的值为text/xml或者application/xml。
- status: HTTP状态码。eg: 200、404
- statusText: HTTP状态码的原因短语。eg:OK
- readyState:异步AJAX时用。表示请求/响应整个过程所处的阶段
- onreadystatechange:存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
3.1 、发送同步请求
如果将open方法的第三个参数设为false,即为同步请求,当收到服务器的响应后,相应的数据会自动填充到上面介绍的XHR对象的属性中。
当客户端收到以上信息后,首先要判断HTTP状态码来确认响应是否成功,状态码在200-300之间表示请求成功,同时304代表请求资源未被修改,可使用浏览器本地缓存。如果成功就可以获取响应报文主体中的数据了。
xhr.open('get', 'http://www.baidu.com', false)
xhr.send(null)
if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) { // 校验HTTP状态码
console.log(xhr.responseText); // 输出响应的文本
} else {
console.error(xhr.status, xhr.statusText); // 打印其他HTTP状态码
}
完整代码:参见前面
3.2 、发送异步请求
如果将open方法的第三个参数设为true
,即为异步请求。然后我们需要设置一个存储函数onreadystatechange
来一直监听服务器响应的数据,当满足监听事件的判定条件后,返回异步的响应数据。
- XHR的
readyState属性,表示请求/响应整个过程所处的阶段,它有五个值分为对应五个阶段:
- 0:未初始化。未调用open()方法。
- 1:启动。已经调用open()方法,但未调用send()方法。
- 2:发送。已调用send()方法,但未收到响应。
- 3:接收。
所有响应头部已经收到,响应体开始接收但未完成
。 - 4:完成。已经接受到全部响应数据。
readyState的值每变化一次,都会触发一次readStatechange事件
,我们定义一个事件处理函数onreadStatechange(),并监听readyState == 4状态,就可以得知响应数据已全部收到,并进行下一步操作。
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){ // 判断请求响应过程阶段,4 阶段代表已接收到数据
if (xhr.status >=200 && xhr.status < 300 || xhr.status == 304) { // 校验HTTP状态码
console.log(xhr.responseText); // 输出响应的文本
} else {
console.error(xhr.status, xhr.statusText); // 打印其他HTTP状态码
}
}
};
xhr.open('get', 'example.txt', true); // 初始化xhr实例,或者说启动请求
xhr.send(null); // 设置HTTP请求携带参数,null为不带参数
完整代码:参见前面
三、XHR2
XMLHttpRequest1级 只是把已有的XHR对象的实现细节描述了出来,而XMLHttpRequest2级则进一步发展了XHR。
1、超时设定
这涉及到timeout 和 ontimeout两个事件
当超出了设置时间
浏览器还未收到响应
请求就会自动终止,就会触发timeout
事件,进而会调用ontimeout事件
处理程序。
同时timeout也是XHR的一个属性,用于设置这个时间阈值。下面是用法:
xhr.open('get', 'http://www.baidu.com', true)
xhr.timeout = 1000 // 时间阈值设为1秒
xhr.ontimeout = function() {
alert('timeout!')
}
xhr.send(null);
上面例子设置为1000毫秒,意味着如果请求在秒钟内还没有返回,就会自动终止,然后会调用timeout事件,进而调用ontimeout。但此时readystate可能已经改变为4了,这意味着会调用onreadyetatechange事件处理程序。可是,如果在超时终止请求之后再访问status属性,就会导致错误。
为避免浏览器报告错误,可以将检查status属性的语句封装在一个try-catch语句中
。
2、进度事件
(1)load事件
load事件用于简化对readState值的判断
,响应数据全部接收完毕后(也就是readState == 4)会触发load事件
,使用onload事件处理函数进行后续操作。
onload会接收一个event对象,其中event.target属性等于XHR对象,当然我们在定义这个事件处理函数时也可以不传入这个参数,来看下面的用法:
xhr.onload = function () {
if(xhr.status >=200 && xhr.status < 300 || xhr.status == 304) {
console.log(xhr.responseText); // 输出响应的文本
} else {
console.error(xhr.status, xhr.statusText); // 打印其他HTTP状态码
}
}
xhr.open('get', 'http://www.baidu.com', true)
xhr.send(null)
这样就不用去关心readyState值的变化情况了。当然如果想在特定readyState值上做一些逻辑处理,还是要用之前的方法。
(2)progress事件
progress事件会在浏览器接收数据期间
周期触发,代表整个请求过程的进度
,它的事件处理程序onprogress接收一个event对象,event.target是XHR对象,另外event还有三个属性:
- lengthComputable:Boolean值,进度信息是否可用。
- position:已经接收到的字节数。
- totalSize:总共要接收的字节数,被定义在响应报文的Content-Length字段中。
如果响应报文中有Content-Length字段,那么我们就可以创建一个进度指示器,如下:
xhr.onload = function(event){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
}else{
alert("unsuccessful:" + xhr.status);
}
};
//为了确保正常执行,必须在调用open()前添加onprogress时间处理程序
//每次触发onprogress事件,都会以新的状态信息更新HTML元素的内容。
xhr.onprogress = function(event){
var divStatus = docuemnt.getElementById('status');
if(event.lengthComputable){
divStatus.innerHTML = 'Received' + event.position + "of" + event.totalSize + 'bytes';
}
};
xhr.open('get','aledada.php',true);
xhr.send(null);
3、FromData
文章刚开始为了提交表单数据,我们需要用setRequestHeader() 和 serialize(form),很麻烦的。所以为了方便,FormData诞生了。
FormData类型其实是在XMLHttpRequest 2级定义的,它是为序列化表
以及创建与表单格式相同的数据(当然是用于XHR传输)提供便利。又是用
注意:必须用POST方法提交
。
具体细节操作见:FormData详解
这里直接提供一个实例:
<form action="#" name="form1">
<select name="a">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</form>
<div id="result"></div>
<script type="text/javascript">
var oForm = document.forms.form1;
var result = document.getElementById('result');
oForm.onchange = function(){
//创建xhr对象
var xhr;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
//异步接受响应
xhr.onload = function(event){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
//实际操作
result.innerHTML = xhr.responseText;
}else{
alert("unsuccessful:" + xhr.status);
}
};
//发送请求
xhr.open('post','t1.php' ,true);
xhr.send(new FormData(oForm)); //创建FormData对象,并将其初始化
}
</script>