AJAX
- 概述,Asynchronous JavaScript + XML
- 使用AJAX可以通过HTTP协议向服务器请求数据,做到在不重新加载整个网页的情况下,对网页的某部分进行更新
- Ajax 技术核心是 XMLHttpRequest 对象,提供了向服务器发送请求和解析服务器响应的接口
XHR对象
- XHR可以通过HTTP协议与服务器交换数据
- open方法,open方法用于创建HTTP请求,但是请求并未发送
- setRequestHeader方法,用于向请求添加HTTP头
- setRequestHeader(name, value),参数name定义HTTP请求头部的名称,参数value定义HTTP请求头部的值
- setRequestHeader方法必须在open方法调用之后、send方法之前调用,否则会出现异常
- setRequestHeader方法可以连续调用多次,如果已经存在同名的HTTP头时,最终结果是追加而不是覆盖
- timeout属性
- timeout属性用于设置HTTP请求的超时时间,单位毫秒。当发生超时时,会触发ontimeout事件。在IE中,超时属性只能在调用 open() 方法之后且在调用 send() 方法之前设置
- upload属性
- upload用于在数据传输到服务器时收集一些传输信息,比如上传了多少字节,总共多少字节等,其里面还包含了一些事件回调。
- send方法
- 用于发送open方法创建的HTTP请求
- abort方法
- 当请求发送后如果想终止这个请求,则可以调用abort方法
XHR事件回调
当XHR发送异步请求后,我们无法知道请求是否发生了异常、请求何时到达服务器、服务器何时返回响应数据。XHR为我们提供了很多的事件回调,用来通知我们请求及响应状态的改变
interface XMLHttpRequestEventTarget : EventTarget {
// event handlers
attribute EventHandler onloadstart;
attribute EventHandler onprogress;
attribute EventHandler onabort;
attribute EventHandler onerror;
attribute EventHandler onload;
attribute EventHandler ontimeout;
attribute EventHandler onloadend;
};
interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {
};
interface XMLHttpRequest : XMLHttpRequestEventTarget {
// event handler
attribute EventHandler onreadystatechange;
// states
//XHR的状态定义
const unsigned short UNSENT = 0;
const unsigned short OPENED = 1;
const unsigned short HEADERS_RECEIVED = 2;
const unsigned short LOADING = 3;
const unsigned short DONE = 4;
//用于描述XHR的状态
readonly attribute unsigned short readyState;
// request
[SameObject] readonly attribute XMLHttpRequestUpload upload;
};
- readyState属性用于描述XHR的状态,它有下面五种状态
- onreadystatechange属性可以指定一个回调函数,当XHR的状态(即readyState)发生改变时就会调用该函数,可以在这个回调函数中判断请求是否成功。
事件回调的时机
- upload属性代表上传数据的过程,它是XMLHttpRequestUpload的实例,XMLHttpRequestUpload继承XMLHttpRequestEventTarget接口,XMLHttpRequestEventTarget有7个回调方法,在数据上传的过程中会调用相应的方法。
- XHR也继承XMLHttpRequestEventTarget接口,因此它也拥有这些回调方法,但是它的回调方法大多都是从服务器下载响应数据的过程中触发的
回调函数的参数
- XMLHttpRequestEventTarget里面的回调方法的参数类型为ProgressEvent,ProgressEvent的定义如下
- 所以在onprogress方法回调中,可以通过loaded和total这两个属性来实现上传或者下载的进度条功能
interface ProgressEvent : Event {
readonly attribute boolean lengthComputable;//数据长度是否可计算的
readonly attribute unsigned long long loaded;//已经下载或者上传了多少字节
readonly attribute unsigned long long total;//需要下载或者上传的总字节数
};
事件回调方法的添加方式
- 一种方式是直接为它指定函数的引用
- 还有一种是添加事件监听器
//添加函数
xhr.onloadstart = function(event) {
console.log("onloadstart()");
}
//添加监听器,事件上不加on
xhr.addEventListener("loadstart", function(event) {
console.log("loadstart()");
});
XHR响应
- getResponseHeader方法
- 可以获取HTTP响应头指定键值的数据,getResponseHeader(ByteString name)
- getAllResponseHeaders方法
- 可以获取所有的HTTP响应头的数据,
- status和statusText属性
- status属性表示HTTP响应状态码,即200、404等;statusText属性表示HTTP响应状态的描述文本,即OK、Not Found等
- 可以在发送请求之前设置responseType,用于指定返回的响应数据的类型,
处理响应数据时,需要根据responseType来判断返回的数据类型。
- 当responseType为text或者empty string类型时可以使用responseText属性,为其它类型时调用responseText会发生异常;
- 当responseType为document或者empty responseXML属性,为其它类型时调用responseXML会发生异常;
- 当responseType不是empty string、text、document类型时,需要转换成具体的类型进行解析。
处理响应数据的时机
通过XHR回调事件的触发时机我们可以知道,onreadystatechange回调会触发多次,因此方式二更优
- 一
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
//处理数据
} else {
//其它操作
}
}
}
- 二
xhr.onload = function(event) {
if (xhr.status === 200) {
//处理数据
} else {
//其它操作
}
}
AJAX请求过程
- 创建XHR对象
- 调用open方法
- 不发送数据,只是启动一个请求以备发生
- 它接受三个参数:要发送的请求类型(get、post)、请求的 URL 和表示是否异步
- 在发送GET请求的时候,可能得到缓存的信息,但有时我们想要最新的数据,不要缓存
- 方法一:在url中添加一个唯一的ID:(随机数)
- xhr.open(“GET”,”demo.asp?t=” + Math.random(),true);
- 方法二:用setRequestHeader(header,value)方法向请求添加HTTP头。(关于setRequestHeader在后面讨论)
- xhr.open(“GET”,”demo.asp”,true);
- xhr.setRequestHeader(“If-Modified-Since”,”0”); //设置浏览器不使用缓存
- 方法一:在url中添加一个唯一的ID:(随机数)
- 调用send方法
- 发送数据
- send()方法接受一个参数,作为请求主体发送的数据。如果不需要则必须填 null
- 解析结果
- 收到响应后,响应的数据会自动填充 XHR 对象的属性
- responseText 作为响应主体被返回的文本
- responseXML 如果响应主体内容类型是”text/xml”或”application/xml”,则返回包含响应数据的 XML DOM 文档
- status 响应的 HTTP 状态
- statusText HTTP 状态的说明
- 收到响应后,响应的数据会自动填充 XHR 对象的属性
AJAX同步请求
- 一般不用同步请求
- 同步请求:
- JavaScript会等到服务器响应就绪才继续执行。
- 如果是比较大型的请求或者服务器处于繁忙状态,应用程序会挂起或停止。
- 简单点说就是页面会一直卡到响应内容回来才继续运行
function ajaxFunction () {
//创建 XMLHttpRequest 对象
var xhr ;
try {
xhr = new XMLHttpRequest();
} catch (e) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
alert("你的浏览器不支持 ajax 技术");
return;
}
}
//提出 get 请求
xhr.open('get','js/cuisine_area.json',false);
//提出请求 post 请求
xhr.open('post','js/cuisine_area.json',false);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
//发送请求
xhr.send(null);
//处理服务器返回的内容
if(xhr.status == 200) {
alert(xhr.responseText);
}else {
alert(" 请 求 失 败 ! 状 态 码 为 : " + xhr.status + " , 状 态 信 息 : " + xhr.statusText);
}
}
封装AJAX异步请求
//参数转换方法
//params({name:'tom',age:100})
function params(data) {
var arr = [];
for (var d in data) {
//将参数中键值对编码,形成name='tom'的样式,同时放入数组中
arr.push(encodeURIComponent(d)+"="+encodeURIComponent(data[d]));
}
//数组转化成字符串,每个元素间用&分割
return arr.join("&");//name=tom&age=100
}
//定义封装的ajax请求方法
function ajax (obj) {
//创建XHR对象
var xhr ;
try {
xhr = new XMLHttpRequest();
} catch (e) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
alert("你的浏览器不支持 ajax 技术");
return;
}
}
//拿到 obj.data 进行转换,将对象拼接成字符串形式
obj.data = params(obj.data);
//若为 get 请求,拼接 url
if(obj.method == 'get'){
//查看url中是否有?,没有的话加上?,然后将参数拼接到url后面
//如果已经有了,就加上&,然后后面拼接上参数
obj.url +=(obj.url.indexOf("?")==-1) ? '?'+obj.data : '&'+obj.data;
}
//若 obj.async 参数为 true 则为异步,需要判断 readyState 状态
if(obj.async == true){
xhr.onreadystatechange = function () {
if(xhr.readyState == 4) {
callback();
}
}
}
//打开请求
xhr.open(obj.method,obj.url,obj.async);
//发送请求
if(obj.method == 'get'){
//若为 get 请求,send 传递 null 即可
xhr.send(null);
}else {
//若为 post 请求,需先模拟表单提交,再 send,同时传递数据
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xhr.send(obj.data);
}
//若 obj.async 参数为 false 则为同步
if(obj.async == false){
callback();
}
//回调函数
function callback () {
if(xhr.status == 200) {
//调用对象中的成功获取请求时的函数
obj.success(xhr.responseText);
}else {
alert(" 请 求 错 误 , 状 态 码 :" + xhr.status + ", 状 态 信 息 :" +xhr.statusText);
}
}
}
//调用 ajax,需要传入一个对象,且此对象需要有method,url,async,data属性和success函数
ajax(
{
method:'post',
url :'js/cuisine_area.json',
async : true,
data : {
name:'tom',
age : 10
},
success : function (result) {
alert(result);
}
}
)
jQuery的AJAX请求
$.ajax
这个是jQuery对ajax的最基础封装,通过使用这个函数可以完成异步通讯的绝大部分功能
调用方式:$.ajax({})
- 参数
$.ajax({
//数据的提交方式:get和post
method:。。。
//数据的提交路劲
url:。。。
//是否支持异步刷新,默认是true
async:true/false
//需要提交的数据
data:{}
//服务器返回数据的类型,例如xml,String,Json等
dataType:。。。
//设置请求头
contentType:..
//发送请求前可修改 XMLHttpRequest 对象的函数,XMLHttpRequest
//对象是唯一的参数,这是一个 Ajax 事件。如果返回 false 可以取消本次 ajax 请求
beforeSend(XHR)
//请求成功后的回调函数
success:function(){}
//请求失败后的回调函数
error:function(){}
}
})
- 实例
$.ajax({
url:'/comm/test1.php',
type:'POST', //GET
async:true, //或false,是否异步
data:{
name:'yang',age:25
},
timeout:5000, //超时时间
dataType:'json', //返回的数据格式:json/xml/html/script/jsonp/text
beforeSend:function(xhr){
console.log(xhr)
console.log('发送前')
},
success:function(data,textStatus,jqXHR){
console.log(data)
console.log(textStatus)
console.log(jqXHR)
},
error:function(xhr,textStatus){
console.log('错误')
console.log(xhr)
console.log(textStatus)
},
complete:function(){
console.log('结束')
}
})
$.post
这个函数其实就是对$.ajax进行了更进一步的封装,只能采用POST方式提交。只能是异步访问服务器,,不能进行错误处理
url:发送请求地址。
data:待发送 Key/value 参数。
callback:发送成功时回调函数。
type:返回内容格式,xml, html, script, json, text,_default。
实例
$.post({
data:"name=tom",
url:"../js/cuisine_area.json",
contentType: "application/x-www-form-urlencoded",
success : function (msg) {
var str = msg;
console.log(str)
$('div').append("<ul></ul>");
for(var i=0; i<msg.prices.length;i++){
$('ul').append("<li></li>")
$('li').eq(i).text(msg.prices[i])
}
}
});
$.get
只能使用在get提交数据解决异步刷新的方式上
$.getJSON
也就是对返回数据类型为Json进行操作。里边就三个参数,需要我们设置,非常简单:url,[data],[callback]。
$.getJSON(
'/user/login',
{"name":"kitty"},
function(){
//代码
}
)
jQuery form插件
JQuery有一个插件,Jquery Form,通过引入此js文件,我们可以模仿表单Form来支持Struts2的域驱动模式,进行自动数据的封装。用法和$.ajax类似,看一下实际的例子,这里写一个保存用户的前台代码:
$(function(){
var options = {
beforeSubmit : function() {
//提交前需要做的功能
},
success : function(result) {
//返回成功以后需要的回调函数
if ( result.success ) {
//成功后代码;
} else {
//失败的代码;
}
// 启用保存按钮
$("#insertBtn").attr("disabled", false);
},
clearForm : true
};
//通过Jquery.Form中的ajaxForm方法进行提交
$('#orgForm').ajaxForm(options);
});