jQuery源码分析系列(37) : Ajax 总结
综合前面的分析,我们总结如下3大块:
- jQuery1.5以后,AJAX模块提供了三个新的方法用于管理、扩展AJAX请求
- 前置过滤器 jQuery. ajaxPrefilter
- 请求分发器 jQuery. ajaxTransport
- 类型转换器 ajaxConvert
- 为了整体性与扩展性考虑,把整个结构通过Deferred实现异步链式模型,Promise对象可以轻易的绑定成功、失败、进行中三种状态的回调函数,然后通过在状态码在来回调不同的函数就行了
- 出于同源策略考虑,存在跨域问题,所以ajax内部的处理总的来分2大块
- 基于XMLHttpRequest的ajax请求
- 基于script的jsonp跨域请求
引入Deferred统一回调体系
jQuery的链式方法是大是通过返回this的引用,但是ajax的链式不是那么简单的,因为ajax可以异步操作,所以返回的是一个异步模型对象Promise
当然如果只是deferred = jQuery.Deferred() 返回这个对象也是没意义的,因为无法关联到实际的数据
所以jquery内部构建了一个增强版的jqXHR对象,除了混入Promise模型,还增强了一些方法与接口
jqXHR 扩充基本的方法与接口
jqXHR = {
// 准备状态
readyState: 0,
// Builds headers hashtable if needed
// 如果需要,创建一个响应头参数的表
getResponseHeader: function(key) {
var match;
// 如果状态为2,状态2表示ajax完成
if (state === 2) {
// 如果没有相应头
if (!responseHeaders) {
// 相应头设空
responseHeaders = {};
// 组装相应头
while ((match = rheaders.exec(responseHeadersString))) {
responseHeaders[match[1].toLowerCase()] = match[2];
}
}
// 响应头对应的key的值
match = responseHeaders[key.toLowerCase()];
}
return match == null ? null : match;
},
// Raw string
// 返回响应头字符串
getAllResponseHeaders: function() {
// 看看是否接收到了,接收到直接返回,否则为null
return state === 2 ? responseHeadersString : null;
},
// Caches the header
// 设置请求头
setRequestHeader: function(name, value) {
var lname = name.toLowerCase();
if (!state) {
// 如果requestHeadersNames[ lname ]不为空,
// 则requestHeadersNames[ lname ]不变,name设置为该值
// 否则,requestHeadersNames[ lname ]不空,
// 则requestHeadersNames[ lname ]设置为name,
// 该映射关系用于避免用户大小写书写错误之类的问题,容错处理
name = requestHeadersNames[lname] = requestHeadersNames[lname] || name;
//现在的name是对的,或者是第一次设置这个name,不需要容错
//设置请求头对应值
requestHeaders[name] = value;
}
return this;
},
// Overrides response content-type header
// 重写相应头content-type
overrideMimeType: function(type) {
if (!state) {
s.mimeType = type;
}
return this;
},
// Status-dependent callbacks
// 对应状态的回调函数集
statusCode: function(map) {
var code;
if (map) {
//如果状态小于2,表示旧的回调可能还没有用到
if (state < 2) {
for (code in map) {
// Lazy-add the new callback in a way that preserves old ones
// 用类似链表的方式添加,以保证旧的回调依然存在
statusCode[code] = [statusCode[code], map[code]];
}
} else {
// Execute the appropriate callbacks
// 无论Deferred成功还是失败都执行当前状态回调
jqXHR.always(map[jqXHR.status]);
}
}
return this
},
// Cancel the request
abort: function(statusText) {
var finalText = statusText || strAbort;
if (transport) {
transport.abort(finalText);
}
done(0, finalText);
return this;
}
};
看看我们ajax的写法
$.ajax({
url: "php.html",
context: document.body,
complete: function() {
console.log(this)
}
}).done(function() {
console.log(this)
});
链式了一个done方法,done是Promise模型中的成功回调,因为ajax返回的是jqXHR对象
所以jqXHR就需要混入Promise模型
deferred.promise(jqXHR).complete = completeDeferred.add;
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;
看ajax源码前需要了解回到队列与Deferreds
jqXHR混入了Promise模型处理,当然只能读防止修改,之外还增加了一个complete的的回调队列

具体怎么使用,看后面
for (i in {
success : 1,
error : 1,
complete : 1
}) {
jqXHR[i](s[i]);
}
很巧妙的一个处理,把用户配置文件中的回调函数给注册到这个jqXHR的回调体系中
所以就把所有的有关回调都绑定到了jqXHR对象上了
ajax提供3种事件通知接口
1 提供全局事件,外部的视图可以根据ajax状态进行改变
2 提供内部事件接口,根据流程做相对应的处理
3 提供链式事件接口,通过Promise实现
当ajax开始时模拟全局事件,ajaxStart
这里主要利用了jQuery.event.trigger和jQuery.fn.trigger模拟发事件
if (fireGlobals && jQuery.active++ === 0) {
// 则通过jQuery.event.trigger模拟触发
jQuery.event.trigger("ajaxStart");
}
ajax发送消息,触发ajaxSend
/**
* 全局事件ajaxSend
* 如果需要,对特定对象触发全局事件ajaxSend
*/
if (fireGlobals) {
globalEventContext.trigger("ajaxSend", [jqXHR, s]);
}
结束时触发ajaxSuccess或ajaxError,再出发ajaxComplete,如果全部ajax结束则触发ajaxStop。
if (fireGlobals) {
globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [jqXHR, s, isSuccess ? success : error]);
}
// Complete
completeDeferred.fireWith(callbackContext, [jqXHR, statusText]);
if (fireGlobals) {
globalEventContext.trigger("ajaxComplete", [jqXHR, s]);
// Handle the global AJAX counter
if (!(--jQuery.active)) {
jQuery.event.trigger("ajaxStop");
}
}
关于缓存数据
如果我们的请求为GET的时候的处理,用户通过data自定义了一些数据,那么这些数据只能通过拼接成url传递给服务端
我们需要通过给地址附加参数_=xxx来避免缓存
if (s.cache === false) {
s.url = rts.test(cacheURL) ?
// If there is already a '_' parameter, set its value
cacheURL.replace(rts, "$1_=" + ajax_nonce++) :
// Otherwise add one to the end
cacheURL + (ajax_rquery.test(cacheURL) ? "&" : "?") + "_=" + ajax_nonce++;
}
从jQuery 1.5开始,$.ajax() 返回XMLHttpRequest(jqXHR)对象,该对象是浏览器的原生的XMLHttpRequest对象的一个超集。
例如,它包含responseText和responseXML属性,以及一个getResponseHeader()方法。
当传输机制不是是XMLHttpRequest时(例如,一个JSONP请求脚本,返回一个脚本 tag 时),jqXHR对象尽可能的模拟原生的XHR功能。
从jQuery 1.5.1开始, jqXHR对象还包含了overrideMimeType方法 (它在jQuery 1.4.x中是有效的,但是在jQuery 1.5中暂时的被移除)。
.overrideMimeType() 方法可能用在beforeSend()的回调函数中,
例如,修改响应的Content-Type信息头:
$.ajax({
url: "http://fiddle.jshell.net/favicon.png",
beforeSend: function ( xhr ) {
xhr.overrideMimeType("text/plain; charset=x-user-defined");
}
}).done(function ( data ) {
if( console && console.log ) {
console.log("Sample of data:", data.slice(0, 100));
}
});
从 jQuery 1.5 开始,$.ajax()返回的jqXHR对象 实现了 Promise 接口, 使它拥有了 Promise 的所有属性,方法和行为。(见Deferred object获取更多信息)。
为了让回调函数的名字统一,便于在$.ajax()中使用。jqXHR也提供.error() .success()和.complete()方法。这些方法都带有一个参数,该参数是一个函数,此函数在 $.ajax()请求结束时被调用,并且这个函数接收的参数,与调用 $.ajax()函数时的参数是一致。这将允许你在一次请求时,对多个回调函数进行赋值,甚至允许你在请求已经完成后,对回调函数进行赋值(如果该请求已经完成,则回调函数会被立刻调用)。
更多的更多大家还是仔细参考API吧
jQuery源码分析系列(37) : Ajax 总结的更多相关文章
- jQuery源码分析系列(36) : Ajax - 类型转化器
什么是类型转化器? jQuery支持不同格式的数据返回形式,比如dataType为 xml, json,jsonp,script, or html 但是浏览器的XMLHttpRequest对象对数据的 ...
- jQuery源码分析系列(31) : Ajax deferred实现
AJAX的底层实现都是浏览器提供的,所以任何基于api上面的框架或者库,都只是说对于功能的灵活与兼容维护性做出最优的扩展 ajax请求的流程: 1.通过 new XMLHttpRequest 或其它的 ...
- jQuery源码分析系列(33) : AJAX中的前置过滤器和请求分发器
jQuery1.5以后,AJAX模块提供了三个新的方法用于管理.扩展AJAX请求,分别是: 1.前置过滤器 jQuery. ajaxPrefilter 2.请求分发器 jQuery. ajaxTran ...
- jQuery源码分析系列(34) : Ajax - 预处理jsonp
上一章大概讲了前置过滤器和请求分发器的作用,这一章主要是具体分析每种对应的处理方式 $.ajax()调用不同类型的响应,被传递到成功处理函数之前,会经过不同种类的预处理(prefilters). 预处 ...
- jQuery源码分析系列(30) : Ajax 整体结构
开头引用一段 想起一句话:前端研究,研究个屁~ 的确如此呀.补充下联:前端设计,设计个屁~ 前端目前最大的困境是,如 HTML 一样,无论你承不承认,市场上并不太需要 HTML 高手 其实这里引发一个 ...
- jQuery源码分析系列(35) : Ajax - jsonp的实现与原理
ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本 json核心就是:允许用户传递一个callba ...
- jQuery源码分析系列
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...
- [转]jQuery源码分析系列
文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...
- jQuery源码分析系列(转载来源Aaron.)
声明:非本文原创文章,转载来源原文链接Aaron. 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAa ...
随机推荐
- Unity插件使用总结
移动文件夹位置会引起错误的插件:EasySave2.MaterialUI.Gamestrap UI.Beautify
- oracle EXP导出一张表时使用query参数指定where条件
oracle exp 导出一个表的部分内容,使用query参数可加上SQL的where条件进行过滤 注意:如果需要使用到日期字符串格式等单引号,需要使用双引号将where条件括起来,而且双引号要用\做 ...
- ListView总结
ListView类作为在Android开发中经常会使用到的组件,作为新手,还是感到这一块变化形式还是很多的,需要慢慢学习.现在这里大概总结一下. 基于数组的ListView:使用android:ent ...
- Python 进程间通信
from multiprocessing import Process,Queue import os,time,random def write(q): print('Process to writ ...
- 关于使用iframe嵌套页面的跳转方式
一.背景A,B,C,D都是jsp,D是C的iframe,C是B的iframe,B是A的iframe,在D中跳转页面的写法区别如下. 二.JS跳转window.location.href.locatio ...
- e.preventDefault() e.stopPropagation()和return false的区别
e.preventDefault(); //阻止事件的默认行为,比如a标签的转向,但不阻止事件的冒泡传播e.stopPropagation() //阻止事件的冒泡传播,但不阻止其默认行为returne ...
- 代码编辑器Sublime Text 3 免费使用方法与简体中文汉化包下载
Sublime Text这款代码编辑器是Jeff 一直都在使用的,前段时间转用到版本3,因为感觉Sublime Text 3 启动速度更加快,运行更加流畅——虽然3 还是在Beta 阶段.下面就直接分 ...
- 关于IOS浏览器:document,body的click事件触发规则
今天做了个手机页面,点击某个按钮->弹出菜单,再点击菜单以外的任意位置->关闭菜单,在其他浏览器里面没有问题,但是在IOS浏览器中并不会关闭. 网上解决这个bug的帖子很多,这篇帖子主要是 ...
- Matlab 视频与图像之间的相互转换
matlab版本是2015b,其中更新了部分函数库之前网上相关程序不适用于新版本,在此提供适用于新版本的程序: 帧序列转换为视频 function video = frames2video(frame ...
- mysql 连接慢的问题(超过了1秒)
http://www.cnblogs.com/isenhome/p/5133547.html 症状描述 本机连接mysql速度很快 远程ping mysql主机速度正常 远程连接mysql速度需要等待 ...