jQuery1.9.1源码分析系列(十六)ajax之ajax框架
AJAX简介
AJAX是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
您应当具备的基础知识
在继续学习之前,您需要对下面的知识有基本的了解:
HTML/XHTML
CSS
JavaScript/DOM
如果您希望首先学习这些项目,请在我们的首页访问这些教程。
什么是AJAX?
AJAX=异步JavaScript和XML。
AJAX是一种用于创建快速动态网页的技术。
通过在后台与服务器进行少量数据交换,AJAX可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
传统的网页(不使用AJAX)如果需要更新内容,必需重载整个网页面。
有很多使用AJAX的应用程序案例:新浪微博、Google地图、开心网等等。
GoogleSuggest
在2005年,Google通过其GoogleSuggest使AJAX变得流行起来。
GoogleSuggest使用AJAX创造出动态性极强的web界面:当您在谷歌的搜索框输入关键字时,JavaScript会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。
今天就开始使用AJAX
AJAX基于已有的标准。这些标准已被大多数开发者使用多年。
既然是ajax框架,那么闲谈一谈jQuery的ajax处理思路。
现在的浏览器都支持ajax,只不过不同的浏览器使用方法可能有不同(IE使用newwindow.ActiveXObject("Microsoft.XMLHTTP"),标准浏览器使用newwindow.XMLHttpRequest())。如果按照这种思路,貌似jQajax只需要做好兼容处理就行了?
不是的,原生的ajax有一个说大不大说小不小的缺点——不支持跨域(同源策略由来已久,自行百度)。所以jQajax添加了这方面的处理,jQajax是如何解决跨域问题的?
<imgsrc="http://img2.imgtn.bdimg.com/it/u=2406301718,2822592556&fm=21&gp=0.jpg"/>
是能取到图片的,很明显图片的路径和你的服务端不是一个域的。你可以试试看所有的带有src属性的标签都不受同源策略的影响。所以,jQuery就使用了这个属性,对于跨域请求使用script标签的src来请求路径。
然后jQuery在加上对ajax事件的三种监听方式:
1.全局事件:$(document).on(‘ajaxStart',func);
2.ajax设置回调项:$.ajax({url:"php.html",complete:func});
3.deferred绑定方式:$.ajax(…).done(func);
基本上这就是jQajax所做的事情。
在正真进入ajax框架核心之前,先来分析一jQuery准备的几个序列化提交表单的函数。
a.表单序列化
所谓的表单序列化即将表单需要提交的内容组成类似:“key=value&key=value…”形式的字符串。
序列化用到三个函数:
jQuery.fn.serialize()(序列化函数,筛选出表单中需要提交的数据并以序列化字符串方式返回,形如:“key=value&key=value…”)
jQuery.fn.serializeArray()(筛选出表单中需要提交的数据并以key/value键值对的对象数组格式返回,返回[{name:'key',value:'select1'},{name:'selectM',value:'selectM1'},{name:'selectM',value:'selectM2'},{name:'key2',value:0}…])
jQuery.param(serializeArray,traditional)(将key/value键值对的对象数组序列化为“key=value&key=value…”字符串)。
serialize直接调用jQuery.param(this.serializeArray())即可。
serializeArray的源码如下:主要进行三个步骤:提取表单元素、过滤出满足提交条件的表单元素、组合成key/value键值对的对象数组
serializeArray:function(){
//将form中的表单相关的元素取出来组成数组
returnthis.map(function(){
//表单节点有elements这个特征
varelements=jQuery.prop(this,"elements");
returnelements?jQuery.makeArray(elements):this;
})
//过滤出为需要提交的表单元素(有name名称、非disabled元素、非提交按钮等元素、checkbox/radio的checked的元素)
.filter(function(){
vartype=this.type;
//使用.is(":disabled")过滤掉不可用的表单元素
returnthis.name&&!jQuery(this).is(":disabled")&&
rsubmittable.test(this.nodeName)&&!rsubmitterTypes.test(type)&&
(this.checked||!manipulation_rcheckableType.test(type));
})
//将表单提交元素组成name和value的对象数组
.map(function(i,elem){
varval=jQuery(this).val();
returnval==null?
null:
jQuery.isArray(val)?
jQuery.map(val,function(val){
return{name:elem.name,value:val.replace(rCRLF,"\r\n")};
}):
{name:elem.name,value:val.replace(rCRLF,"\r\n")};
}).get();
}
需要注意的是jQuery的过滤结果符合正常的表单提交结果://过滤出为需要提交的表单元素(有name名称、非disabled元素、非提交按钮等元素、checkbox/radio的checked的元素)
param函数源码如下:主要进行两个处理:将key/value成作为URI组件编码(保证key和value不会出现特殊符号,即保证了“=”分割的正确性)、使用“&”链接并将空白符被替换成了"+"
jQuery.param=function(a,traditional){
varprefix,
s=[],
add=function(key,value){
//如果value是函数,执行他得到真正的value
value=jQuery.isFunction(value)?value():(value==null?"":value);
//把key和value作为URI组件编码,保证key和value不会出现特殊符号,即保证了“=”分割的正确性
s[s.length]=encodeURIComponent(key)+"="+encodeURIComponent(value);
};
...
//传入的是数组,假设他是一个form表单键值对数组
if(jQuery.isArray(a)||(a.jquery&&!jQuery.isPlainObject(a))){
//序列化表单元素
jQuery.each(a,function(){
add(this.name,this.value);
});
}else{
...
}
//返回序列化结果,注意:空白符被替换成了"+"
returns.join("&").replace(r20,"+");
};
其中encodeURIComponent详细点击查看
b.ajax的事件监听
给ajax绑定事件有三种方式
1.全局事件:$(document).on(‘ajaxStart',func);
2.ajax设置回调项:$.ajax({url:"php.html",complete:func});
3.deferred绑定方式:$.ajax(…).done(func);
接下来我们一一讲解他们的实现。
全局事件(ajaxStart/ajaxStop/ajaxComplete/ajaxError/ajaxSuccess/ajaxSend)
使用.on事件绑定这种通用方式我们毫无疑问是可以绑定ajax监听事件,除此之外还可以直接使用$(…).ajaxStart(func)来绑定事件。他们的实现也是用.on来绑定。
jQuery.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(i,type){
jQuery.fn[type]=function(fn){
returnthis.on(type,fn);
};
});
触发事件比较简单,在进行ajax处理过程中在合适的时机直接使用jQuery.event.trigger直接触发。以ajaxStart为例
//如果此时没有正在执行的请求,则触发ajaxStart事件
if(fireGlobals&&jQuery.active++===0){
jQuery.event.trigger("ajaxStart");
}
ajax设置回调项(beforeSend/complete/success/error)
触发设置回调项分两种:beforeSend直接在适当的时机调用。源码
//调用beforeSend回调,如果回调返回失败或abort则返回中止
if(s.beforeSend&&(s.beforeSend.call(callbackContext,jqXHR,s)===false||state===2)){
//中止如果没有准备好
returnjqXHR.abort();
}
complete/success/error则利用Deferred的特性将回调添加到延时队列,等待延时状态处理。源码
//创建最终选项对象
s=jQuery.ajaxSetup({},options)
...
deferred=jQuery.Deferred(),
completeDeferred=jQuery.Callbacks("oncememory"),
...
//添加延时事件
deferred.promise(jqXHR).complete=completeDeferred.add;
jqXHR.success=jqXHR.done;
jqXHR.error=jqXHR.fail;
//安装回调到deferreds上
for(iin{success:1,error:1,complete:1}){
jqXHR[i](s[i]);
}
//在ajax请求完成的处理函数中执行completeDeferred的延时列表
functiondone(){
...
//执行Complete处理
completeDeferred.fireWith(callbackContext,[jqXHR,statusText]);
...
}
deferred方式绑定回调
Deferred方式绑定事件就不用特别说明了,因为ajax本身就是一个延时对象。直接使用$.ajax(…).done(fn).fail(fn).progress(fn).always(fn).then(fn)。源码
deferred=jQuery.Deferred(),
completeDeferred=jQuery.Callbacks("oncememory"),
...
deferred.promise(jqXHR).complete=completeDeferred.add;
...
returnjqXHR;