jQuery ajax主函数分析Word格式文档下载.docx
《jQuery ajax主函数分析Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《jQuery ajax主函数分析Word格式文档下载.docx(22页珍藏版)》请在冰豆网上搜索。
responseHeaders){
//相应头设空
responseHeaders={};
while((match=rheaders.exec(responseHeadersString))){
//组装相应头
responseHeaders[match[1].toLowerCase()]=match[2];
}
//响应头对应的key的值
match=responseHeaders[key.toLowerCase()];
//返回
returnmatch==null?
null:
match;
},
//返回响应头字符串
getAllResponseHeaders:
function(){
//看看是否接收到了,接收到直接返回,否则为null
returnstate===2?
responseHeadersString:
null;
//设置请求头
setRequestHeader:
function(name,value){
varlname=name.toLowerCase();
//如果state不为0
state){
//如果requestHeadersNames[lname]不为空,
//则requestHeadersNames[lname]不变,name设置为该值
//否则,requestHeadersNames[lname]不空,
//则requestHeadersNames[lname]设置为name,
//该映射关系用于避免用户大小写书写错误之类的问题,容错处理
name=requestHeadersNames[lname]=requestHeadersNames[lname]||name;
//现在的name是对的,或者是第一次设置这个name,不需要容错
//设置请求头对应值
requestHeaders[name]=value;
returnthis;
//重写相应头content-type
overrideMimeType:
function(type){
s.mimeType=type;
//对应状态的回调函数集
statusCode:
function(map){
varcode;
//如果map存在,准备组装
if(map){
//如果状态小于2,表示旧的回调可能还没有用到
if(state<
2){
//遍历map里面的所有code
for(codeinmap){
//用类似链表的方式添加,以保证旧的回调依然存在
statusCode[code]=[statusCode[code],map[code]];
//状态大于2,证明已经完成了
}else{
//无论Deferred成功还是失败都执行当前状态回调
jqXHR.always(map[jqXHR.status]);
//中断请求
abort:
function(statusText){
varfinalText=statusText||strAbort;
//可以先理解成XHR对象,当然这也不是真正的XHR对象
if(transport){
transport.abort(finalText);
//调用done,表示干完了
done(0,finalText);
};
可是这还没有链式啊!
怎么把jqXHR变成一个Promise呢?
让一个对象拥有另一个对象的方法,大家会想到什么呢?
继承?
不,直接插上去就好了……这里就体现了Javascript“易插拔”的特点……自己乱起的……囧rz……
应该说动态、弱类的特点。
什么意思?
就是将Promise上的方法插到jqXHR对象上就行了。
//在jqXHR粘上promise的所有方法,此时jqXHR就很像一个promise了
//实际上就是用jQuery.extend(jqXHR,promise)而已
//jqXHR刚山寨了xhr对象,又开始山寨promise对象了
//顺便把jqXHR的complete绑上completeDeferred.add
//意思是jqXHR状态完成后调用completeDeferred这个Callbacks列队
//话说promise里面并没有complete这个方法
//后面我们可以看到,作者大人又要给jqXHR插上complete、success、error方法
//Javascript就是这样简单,即插即用……囧rz
deferred.promise(jqXHR).complete=completeDeferred.add;
//绑定jqXHR.success为promise里面的done方法
jqXHR.success=jqXHR.done;
//绑定jqXHR.error为promise里面的fail方法
jqXHR.error=jqXHR.fail;
这样子直接插上去在强类语言中是做不到的,当然也可以用组合模式来实现一个对象拥有多个对象的方法,但是却无法动态的去给对象添加各种方法。
强类语言会限制对象一辈子只能“会”那么几种“方法”,Javascript的对象可以在生命周期内随意“学习”各种“方法”。
所以说,强类语言和Javascript的对象模型是有差别的,将设计模式生搬硬套进Javascript或许是错误的。
我们再举个例子,比如如果用所谓的Javascript组合模式来重写上面的代码可能会是这样的:
//定义局部变量deferred和completeDeferred
functionJQXHR(){
//定义jqXHR的属性和方法
for(iindeferred.promise){
this[i]=this.promise[i];
plete=completeDeferred.add;
this.success=this.done;
this.error=this.done
}
varjqXHR=newJQXHR();
大家觉得哪个好呢?
变成上面的样子主要是因为要解决下面两个问题:
1.jqXHR由于是暴露在外的,他不能包含deferred和completeDeferred,不允许用户在外部操作这两个对象的状态。
2.deferred和completeDeferred也不能成为jqXHR的私有变量,因为还要更具ajax事件触发。
提供全局事件,使得UI可以根据ajax状态进行改变
这里主要利用了jQuery.event.trigger和jQuery.fn.trigger模拟发事件。
//如果需要,而且全局事件没有被触发过
if(fireGlobals&
&
jQuery.active++===0){
//则通过jQuery.event.trigger模拟触发
jQuery.event.trigger("
ajaxStart"
);
当ajax开始时模拟全局事件,ajaxStart。
//如果需要,对特定对象触发全局事件ajaxSend
if(fireGlobals){
globalEventContext.trigger("
ajaxSend"
[jqXHR,s]);
ajax发送消息,触发ajaxSend。
//如果需要触发全局事件
//对指定元素触发事件ajaxSuccess或者ajaxError
globalEventContext.trigger(isSuccess?
"
ajaxSuccess"
:
ajaxError"
[jqXHR,s,isSuccess?
success:
error]);
//回调完成后的Callbacks队列
completeDeferred.fireWith(callbackContext,[jqXHR,statusText]);
//对指定元素触发事件ajaxComplete
ajaxComplete"
//该ajax触发完毕,标记active减1,如果为0,证明所有ajax结束
(--jQuery.active)){
//触发ajaxStop事件
ajaxStop"
}
结束时候触发ajaxSuccess或ajaxError,再出发ajaxComplete,如果全部ajax结束则触发ajaxStop。
是否许使用缓存数据
//如果不需要content
//看看需不需要加其他信息
s.hasContent){
//如果data存在,那么已经序列化
if(s.data){
//添加到cacheURL中
cacheURL=(s.url+=(ajax_rquery.test(cacheURL)?
"
?
)+s.data);
//删除掉则后面就不会被发送出去了
deletes.data;
//看看是否需要避免数据从缓存中读取
if(s.cache===false){
s.url=rts.test(cacheURL)?
//如果已经有_参数,那么设置他的值
cacheURL.replace(rts,"
$1_="
+ajax_nonce++):
//否则添加一个_=xxx在URL后面
cacheURL+(ajax_rquery.test(cacheURL)?
)+"
_="
+ajax_nonce++;
通过给地址附加参数_=xxx来避免缓存。
//看看需不需要设置If-Modified-Since和If-None-Match头信息
if(s.ifModified){
if(jQuery.lastModified[cacheURL]){
jqXHR.setRequestHeader("
If-Modified-Since"
jQuery.lastModified[cacheURL]);
if(jQuery.etag[cacheURL]){
If-None-Match"
jQuery.etag[cacheURL]);
以及设置If-Modified-Since和If-None-Match头信息。
//看看是否需要缓存置If-Modified-Since和If-None-Match头
//取得Last-Modified
modified=jqXHR.getResponseHeader("
Last-Modified"
//如果Last-Modified存在
if(modified){
//在jQuery.lastModified[cacheURL]保存Last-Modified
jQuery.lastModified[cacheURL]=modified;
//取得etag
etag"
//如果etag存在
//在jQuery.etag[cacheURL]缓存etag
jQuery.etag[cacheURL]=modified;
缓存If-Modified-Since和If-None-Match头信息。
设置超时
//如果是异步,并且设置了超时
if(s.async&
s.timeout>
0){
//设置超时
timeoutTimer=setTimeout(function(){
jqXHR.abort("
timeout"
},s.timeout);
主要功能分析完了,完整备注代码见下。
完整备注
jQuery.ajax=function(url,options){
//如果url是一个obj,模拟1.5版本以前的方法
if(typeofurl==="
object"
){
options=url;
url=undefined;
//设置options
options=options||{};
vartransport,
//缓存cacheURL
cacheURL,
//响应头
responseHeadersString,
responseHeaders,
//超时控制器
timeoutTimer,
//跨域判定变量
parts,
//是否需要触发全局事件
fireGlobals,
//循环变量
i,
//通过jQuery.ajaxSetup改造参数对象
s=jQuery.ajaxSetup({},options),
//回调指定上下文,也就是他的this
callbackContext=s.context||s,
//全局事件中的相应函数的指定上下文
//有s.context,且是DOM节点,或者jQuery收集器
globalEventContext=s.context&
(callbackContext.nodeType||callbackContext.jquery)?
//通过jQuery包装
jQuery(callbackContext):
//否则为jQuery.event
jQuery.event,
//新建一个deferred
deferred=jQuery.Deferred(),
//deferred完成后的Callbacks队列
completeDeferred=jQuery.Callbacks("
oncememory"
),
statusCode=s.statusCode||{},
//请求头
requestHeaders={},
requestHeadersNames={},
//包装类jqXHR的状态
state=0,
//默认中断消息
strAbort="
canceled"
//赝品xhr,或者说山寨xhr……╮(╯▽╰)╭
//为了能够实现链式操作
//顺便扩展一下xhr对象功能
//还有提供一定的容错处理
jqXHR={
//缓存请求头
};
deferred.promise(jqX