标准的w3c直接提供了XMLHttpRequest方法,咱们主要站在设计的角度来理解,如何设计出低耦合高内聚的代码jquery对Ajax的处理主要体如今对浏览器兼容,数据的处理过滤以及各类事件的封装上,主要有几个部分的扩展javascript
提供快捷接口,提供底层接口,提供数据序列化,提供全局Ajax事件处理php
给document绑定ajaxStart,ajaxComplete回调事件,trgger绑定一个点击事件,经过click触发事件发送一个ajax请求,而且经过complete,done,ajaxStart,ajaxComplete返回状态回调。css
$(document).ajaxStart(function(){html
console.info(arguements)java
}).ajaxComplete(function(){jquery
$(".log").text("");git
});github
$(".trigger").click(function(){ajax
//发送ajax请求express
$.ajax({
url:"index.html",
context:document.body,
complete:function(){
console.info(this);
}
}).done(function(){
console.info(this);
});
});
这里实现比较特别的地方,针对ajax提供3种回调方式:
1,内部回调beforeSend,error,dataFilter,success和complete等
2,外部的done,fail,when,always等
3,全局document上都能捕获到ajax的每一步的回调通知,ajaxStart,ajaxStop,ajaxComplete(),ajaxError(),ajaxSuccess(),ajaxSend(),等
针对ajax的请求,每一步的状态,成功,失败或者进行中,咱们有3种方式能够监听,可是每一种仍是有各自的区别:
1,Ajax的参数回调
2,基于deferred方式的done回调
3,全局的自定义事件的回调
接口的设计优劣
设计1:
tAjax({
url:"index.html",
complete:function(data){
console.log(data);
}
});
若是要实现这种接口调用咱们须要封装下代码,把回调经过实参传递
var tAjax = function(config){
var url = config.url;
var complete = config.complete;
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xhr.open('post', url);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
complete(xhr.responseText);
}
}
}
xhr.send();
}
遮这样的设计能够看作类型工厂模式的封装,好处不用多说在工厂模式里面包含了对象的建立等必要的逻辑,客户端根据传参选择东西的实例化相对的处理,对于库福段来去除了具体的依赖,固然tAjax也能够看作一个外观模式提供的接口,其实就是隐藏了具体的复杂逻辑,提供一个简单的接口,从而下降耦合。
设计2:
tAjax({
url:"index.html",
complete:function(data){
console.info(data);
}
}).done(function(data){
console.info(data);
});
在以前加入了一个done链式处理,固然这里done,实际上是deferred的一个成功处理通知。
var ajax = tAjax({ url: "php.html", complete: function(data) { console.log(data) } }) ajax.done(function(){ //......... })
var tAjax = function(config) { ///参考右图设计二 return { done: function(ourfn) { doneFn = ourfn; } } }
咱们返回了一个 done 对象,这里同样要是对象,由于链式的缘由咱们看外部指定了内部的 done,从而把外部函数给引用到内部的 doneFn 上缓存起来 xhr.staturs 成功后一块儿执行,固然这种设计是有问题的,若是在 done 以后我再链式就确定不行,由于对象的引用错了,那么 jQuery 是如何处理?
设计3:提供document对象的全局处理
$(document).ajaxComplete(function(){
console.info("ajax请求成功");
})
tAjax({
url:"index.html",
complete:function(data){
console.info(data);
}
}).done(function(data){
console.info(data);
})
这里的问题就是把ajax内部的事件,返回给全局捕获了,有点相似css的全局动画事件
这里的设计就是发送一个事件给document便可
jQuery利用了trigger自定义事件触发的globalEventContext.trigger('ajaxComplete',[jqXHR,s]);
具体每一种实如今后面的都会提到,在这里须要你们的有个总体的印象。
设计ajax库须要考虑的问题
ajax的底层实现都是浏览器提供的,因此任何基于api上面的框架或者库,都只是对于功能的灵活与兼容维护性作出最优的扩展,ajax请求的流程:
1.经过new XMLHttpRequest或其余的形式(ie生成ajax的对象xhr.
2.经过xhr.open(type,url,async,username,password)的形式创建一个链接
3.经过etRequestHeader设定xhr的请求头部(request header)
4.经过send(data)请求服务器的数据
5.执行在xhr上注册的onreadstatechange回调处理返回数据。
这几步中,可能会遇到的问题
跨域,json的格式,dataType,Ajax乱码问题,页面缓存,状态的跟踪,不一样平台的兼容
jQuery主要就是解决上面的问题, 以后就在这个基础之上进行扩展, jQuery2.3版本的ajax部分源码大概有1200多行,主要针对ajax模块的重写,增长了几个新的概念,ajax 模块提供了三个新的方法用于管理,扩展ajax请求,分别是:
前置过滤器jQuery.ajaxPrefilter
请求分发器jQuery.ajaxTransport
类型转换器ajaxConvert
除此以后还重写了整个异步队列处理,加入了 deferred,能够将任务完成的处理方式与任务自己解耦合,使用 deferreds 对象,多个回调函数能够被绑定在任务完成时执行,甚至能够在任务完成后绑定这些回调函数。这些任务能够是异步的,也能够是同步的。
好比以前提到的:
在异步机制这章咱们详细的分析了 deferred 的设计,其中提供了 deferred.promise 方法就是把普通对象转化成 deferred 对象了,ajax 就是把 deferred 对象给掺进去可让整个 Ajax 方法变成了一个 deferred 对象,在Ajax方法中返回的是 jqXHR 一个包装对象,在这个对象里面混入了全部实现方法。
ajax: function(url, options) { var jqXHR = {} //ajax对象 deferred = jQuery.Deferred() //转成deferred对象 deferred.promise(jqXHR).complete = completeDeferred.add return jqXHR }
jQuery.ajax 的版本迭代:
为了向后兼容 XMLHttpRequest ,jqXHR 对象将公开下列属性和方法:
readyState status statusText responseXML and/or responseText 当底层的请求分别做出XML和/或文本响应 setRequestHeader(name, value) 从标准出发,经过替换旧的值为新的值,而不是替换的新值到旧值 getAllResponseHeaders() getResponseHeader() abort()
为了实现以上这些功能,jQuery 在对 jqXHR 作2个处理:
// Deferreds deferred = jQuery.Deferred(), //全部的回调队列,无论任什么时候候增长的回调保证只触发一次 completeDeferred = jQuery.Callbacks("once memory"),
给 jqXHR 扩充添加 promise 的属性和方法,而后添加 complete 方法,这里用的是回调列表的 add 方法(即添加回调)
deferred.promise(jqXHR).complete = completeDeferred.add;
此时的 jqXHR 就具备了 promise 的一些特性了与 callback 的回调列队了,固然这里有个重点,返回了一个只读的 deferred 对象,若是返回完整的 deferred 对象,那么外部程序就能随意的触发 deferred 对象的回调函数,颇有可能在 AJAX 请求结束前就触发了回调函数(resolve),这就是与 AJAX 自己的逻辑相违背了。因此为了不不经意间改变任务的内部流程,咱们应该只返回 deferred 的只读版本 deferred.promise(),而后把对应的 done 与 fail 改为别名 success 与 error。
jqXHR.success = jqXHR.done; jqXHR.error = jqXHR.fail
咱们还须要把用户自定的内部回调函数给注册到 jqXHR 对象上。
// 增长回调队列 for (i in { success : 1, error : 1, complete : 1 }) { /** * 把参数的回调函数注册到内部jqXHR对象上,实现统一调用 * 给ajax对象注册 回调函数add * deferred返回complete,error外部捕获 */ jqXHR[i](s[i]); }
经过一个 for 循环把对应的方法都执行了,具体就是这几个:
jQuery1.5 之后,Ajax 模块提供了三个新的方法用于管理、扩展 Ajax 请求,分别是:
前置过滤器 jQuery. ajaxPrefilter 请求分发器 jQuery. ajaxTransport, 类型转换器 ajaxConvert
为何会出现这几个新的概念?由于 ajax 在发送的过程还有不少一系列的处理。
具体看看代码:
jQuery.extend({ //前置过滤器 ajaxPrefilter: addToPrefiltersOrTransports(prefilters), //请求分发器 ajaxTransport: addToPrefiltersOrTransports(transports), });
其实说白了就是把对应的方法制做成函数的形式填充到 prefilters 或者 transports对应的处理包装对象中,用的时候直接执行,每一个函数都保持着各自的引用,种写法的好处天然是灵活,易维护,减小代码量。
因此此时的 prefilters 中的结构能够是这样。
prefilters = { '*': function() { return { send: function() { }, callback: function() { } } } }
前置过滤器和请求分发器在执行时,分别遍历内部变量 prefilters 和 transports,这两个变量在 jQuery 加载完毕后当即初始化,从过闭包的方法填充这个 2 个对象。
ajaxPrefilter 与 ajaxTransport 都是经过 inspectPrefiltersOrTransports 构建器建立的。
prefilters 中的前置过滤器在请求发送以前、设置请求参数的过程当中被调用,调用 prefilters 的是函数 inspectPrefiltersOrTransports ,巧妙的是 transports 中的请求分发器在大部分参数设置完成后,也经过函数 inspectPrefiltersOrTransports 取到与请求类型匹配的请求分发器。
经过(右边代码一)咱们能够看出来:
前置过滤器 prefilters
在每一个请求以前被发送和 $.ajax () 处理它们前处理,设置自定义 Ajax 选项或修改现有选项,简单的说就是一种 hack 的作法,只是说比起事件的那种 hack 写的手法实现更为高明。好比咱们要预过滤器(Prefilters)也能够被用来修改已经存在的选项。
例如,下面的代理服务器跨域请求 http://mydomain.net/proxy/:
$.ajaxPrefilter( function( options ) { if ( options.crossDomain ) { options.url = "http://mydomain.net/proxy/" + encodeURIComponent( options.url ); options.crossDomain = false; } });
若是提供可选的 dataTypes 参数,那么预滤器(prefilter)将只会对知足指定 dataTypes 的请求有效。例如, 如下仅适用于 JSON 和 script 请求给定的预过滤器:咱们能够看看针对 prefilters 的方法其实就是 dataType 为 script,json,jsonp的处理,当咱们动态加载脚本文件好比:
$.ajax({ type : "GET", url : "test.js", dataType : "script" });
因此在 inspectPrefiltersOrTransports 方法中 prefilters[script] 能找到对应的处理方法,因此就会执行。例如 script 的 hack,要强制加上处理缓存的特殊状况和 crossDomain,由于设置 script 的前置过滤器,script 并不必定意思着跨域,跨域未被禁用,强制类型为 GET,不触发全局时间。
jQuery.ajaxPrefilter("script", function(s) { if (s.cache === undefined) { s.cache = false; } if (s.crossDomain) { s.type = "GET"; } });
因此 prefilters 就是在特定的环境针对特定的状况作一些必要的兼容的处理。
请求分发器 transports
请求分发器顾名思义发送请求,那么底层的 ajax 发送请求是经过 send 方法。
xhr.send();
可是 jQuery 对 send 方法作了拆分,把对应的处理放到了 transports 中了,那么 transports 对象也是相似前置处理器经过 jQuery.ajaxTransport 构建,例如 script,send,abort 方法返回出 transports 方法。
transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);
从源码中能够看到 transport 是一个对象,它提供了两种方法,send
和 abort
,内部使用由 $.ajax()
发出请求。transport 是最高级的方法用来加强 $.ajax()
而且应仅做为当预过滤器(prefilters)和转换器(converters)没法知足你的需求的时候的最后的手段。因为每一个请求须要有本身的传输(transport)对象实例,传输不能直接注册。所以,你应该提供一个函数代替返回传输(transport)。
预处理script类型
$.ajax()调用不一样类型的响应,被传递到成功处理函数以前,会通过不一样种类的预处理(prefilters)
预处理的类型取决于由更加接近默认的Content-Type响应,但能够明确使用dataType选项进行设置,若是提供了dataType选项,响应的Content-Type头信息将被忽略。
有效的数据类型是text,html,xml,json,jsonp和script
dataType:预期服务器返回的数据类型,若是不指定,jQuery将自动根据HTTP包MIME信息来智能判断,好比XML MIME类型就被识别为XML,在1.4中,JSON就会生成一个javaScript对象,而script则会执行这个脚本,随后服务器返回的数据会根据这个值解析后,传递给回调函数。
sctipt类型
$.ajax({
type:"GET",
url:"test.js",
dataType:"script",
complete:function(jqXHR,status){
console.info(jqXHR,status);
}
});
若是dataType类型为script的时候,须要处理:
1,执行脚本
2,内容当作纯文本你返回
3,默认状况下不会经过在url中附加查询字符串变量"_=[TIMESTAMP]"进行自动缓存结果,除非设置了cahce参数为true。
4,在运程请求时(不在同一个域下),全部POST请求都将转为GET请求(由于将使用DOM的script标签来加载)
inspectPrefiltersOrTransports(prefilters,s,options,jqXHR)
此时的dataType类型就会通过对应的预处理ajaxPrefilter("script"),其中s.cache(默认为true,dataType为script和jsonp时默认为false)
jQuery.ajaxPrefilter("script",function(s){
if(s.cache === undefined){
s.cache = false;
}
if(s.srossDomain){
s.type = "GET";
}
});
预处理的处理就是将其缓存设置为false,浏览器将不缓存此页面,这将在请求的url的查询字符串中追加一个时间戳参数,以确保每次浏览器下载的脚本被从新请求,工做原理是在GET请求参数中附加"_={timestamp}"在GET请求的地址后加一个时间戳。
json:把响应的结果当作json执行,并返回一个JavaScript对象,若是指定的是json,响应结果做为一个对象,在传递给成功处理函数以前使用jQuery.parseJSON进行解析,解析后的JSON对象能够经过该jqXHR对象的responseJSON属性得到的,json的处理只要是在ajaxConvert方法中把结果给转换成须要是json格式,这是后面的内容,这里主要研究jsonp的预处理。
JSONP:是一个非官方的协议,它容许在服务器端集成Script tags返回到客户端,经过JavaScript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式),json系统开发方法是一种典型的面向数据结构的分析和设计方法,以活动为中心, 一连串的活动的顺序组合成一个完整的工做进程。
JSONP 出现的根源:
JSON和JSONP
与XML相比,JSON是一个轻量的数据交换格式,JSON对象对于JavaScript开发人员充满魅力的缘由在于JSON自己就是JavaScript中的对象。
var ticker = {symbol:'IBM',price:100} 而JSON串就是 {symbol:'IBM',price:100}
index.html 中:
function showPrice(data){ alert("Symbol:" + data.symbol + ", Price:" + data.price) }
因此总结其实json的一个核心点:容许用户传递一个callback参数给服务器端,而后服务器返回数据时会将这个callback参数做为函数名来包裹住json数据,这样客户端就能够随意定制本身的函数来自动处理返回数据了。
jsonp的原理:
ajax和jsonp的区别:
ajax的核心是经过XmlHttpRequest获取飞本页面内容,jsonp的核心是动态添加script标签来调用服务器提供的js,容许用户传递一个callback参数给服务器端,而后服务器端返回数据时会将这个callback参数 做为函数名包裹住json数据,这个客户端就能够随意定制指定的本身的函数来自动处理返回数据了。
$.ajax({
crossDomain :true,
url: 'http://192.168.1.113:8080/github/jQuery/jsonp.php', //不一样的域
type: 'GET', // jsonp模式只有GET是合法的
data: {
'action': 'aaron'
}, // 预传参的数组
dataType: 'jsonp', // 数据类型
jsonp: 'callback', // 指定回调函数名,与服务器端接收的一致,并回传回来
jsonpCallback:"flightHandler",
success: function(json) {
console.log(json);
}
})function flightHandler(data){
console.log(data)
}
function createJsonp(url, complete) {
var script = jQuery("<script>").prop({
async: true,
src: "http://192.168.1.113:8080/github/jQuery/jsonp.php?callback=flightHandler&action=aaron&_=1418782732584"
}).on(
"load error",
callback = function(evt) {
script.remove();
callback = null;
}
);
document.head.appendChild(script[0]);
}
createJsonp()
jquery、ext、dojo 这类库的实现手段其实大同小异,在同源策略下,在某个服务器下的页面是没法获取到该服务器之外的数据的,但 img、iframe、script 等标签是个例外,这些标签能够经过 src 属性请求到其余服务器上的数据。利用 script 标签的开放策略,咱们能够实现跨域请求数据,固然,也须要服务端的配合。通常的 ajax 是不能跨域请求的,所以须要使用一种特别的方式来实现跨域,其中的原理是利用 <script> 元素的这个开放策略。
这里有2个重要的参数:
jsonpCallback:
为 jsonp 请求指定一个回调函数名。这个值将用来取代 jQuery 自动生成的随机函数名。这主要用来让 jQuery 生成一个独特的函数名,这样管理请求更容易,也能方便地提供回调函数和错误处理。你也能够在想让浏览器缓存 GET 请求的时候,指定这个回调函数名。从jQuery 1.5 开始,你也可使用一个函数做为该参数设置,在这种状况下,该函数的返回值就是 jsonpCallback 的结果。
jsonp:
在一个 jsonp 请求中重写回调函数的名字。这个值用来替代在 "callback=?" 这种 GET 或 POST 请求中 URL 参数里的 "callback" 部分,好比 {jsonp:'onJsonPLoad'} 会致使将 "onJsonPLoad=?" 传给服务器。在 jQuery 1.5,设置 jsonp 选项为 false,阻止了 jQuery 从加入 "?callback" 字符串的 URL 或试图使用 "=?" 转换。在这种状况下,你也应该明确设置 jsonpCallback 设置。例如, { jsonp: false, jsonpCallback: "callbackName" }。
当咱们正常地请求一个 JSON 数据的时候,服务端返回的是一串 JSON 类型的数据,而咱们使用 JSONP 模式来请求数据的时候,服务端返回的是一段可执行的 JavaScript 代码,因此咱们可见服务器代码最后一行。
$_GET['callback']).'('. json_encode(array('status'=>1,'info'=>'OK')) .')
就是执行的 backfunc 方法,而后把数据经过回调的方式传递过。
OK,就是整个流程就是:
客户端发送一个请求,规定一个可执行的函数名(这里就是 jQuery 作了封装的处理,自动帮你生成回调函数并把数据取出来供 success 属性方法来调用,不是传递的一个回调句柄),服务端接受了这个 backfunc 函数名,而后把数据经过实参的形式发送出去
咱们发送一个 jsonp 的请求:
$.ajax({ crossDomain:true,//强制跨域 url: ' http://url...’, //不一样的域 type: 'GET', // jsonp模式只有GET是合法的 data: { 'action': 'aaron' }, // 预传参的数组 dataType: 'jsonp', // 数据类型 jsonp: 'backfunc', // 指定回调函数名,与服务器端接收的一致,并回传回来 })
经过 ajax 请求不一样域的实现,jsonp 底层不是靠 XmlHttpRequest 而是 script,因此不要被这个方法给迷惑了。
这里有几个要注意的:
http://192.168.1.113:8080/github/jQuery/jsonp.php?callback=flightHandler&action=aaron&_=1418782732584 ">
而后经过建立脚本动态加载:
<script type="text/javascript" src=" http://192.168.1.113:8080/github/jQuery/jsonp.php?callback=flightHandler&action=aaron&_=1418782732584 "></script>
而后 php 方就会收到 get 请求的参数,经过解析出 callback 执行 callback 这个回调并传递参数。
要处理的几个问题:
1. 采用的是脚本请求的方法,因此虽然 dataType 是 'jsonp' 可是内部仍是按照 script 处理 2. get 请求的后缀拼接,编码的处理 3. 避免缓存的处理
因此流程就会分二步:
分发器执行代码:
当咱们全部的参数都转化好了,此时会通过请求发送器用来处理发送的具体,为何会叫作分发器,由于发送的请求目标,ajax 由于参杂了 jsonp 的处理,因此实际上的请求不是经过 xhr.send(XmlHttpRequest) 发送的,而是经过 get 方式的脚本加载的,因此 transports 对象在初始化构件的时候,会生成 2 个处理器
*: Array[1] 针对xhr方式 script: Array[1] 针对script,jsonp方式
因此 transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR),那么获得的 transport 就会根据当前的处理的类型,来选择采用哪一种发送器(*、script)因此最终的实现就是经过动态加载脚本!
什么是类型转化器?
jQuery 支持不一样格式的数据返回形式,好比 dataType 为 xml、json、jsonp、script、html。可是浏览器的 XMLHttpRequest 对象对数据的响应只有 responseText 与 responseXML 这2种,因此如今我要定义 dataType 为 jsonp,那么所得的最终数据是一个 json 的键值对,因此 jQuery 内部就会默认帮你完成这个转化工做,jQuery 为了处理这种执行后数据的转化,就引入了类型转化器,若是没有指定类型就依据响应头 Content-Type 自动处理数据传输,服务器只能返回字符串形式的,因此若是咱们 dataType 为 jsop 或者 json 的时候服务器返回的数据为:
responseText: "{"a":1,"b":2,"c":3,"d":4,"e":5}"
给转化成:
responseJSON: Object { a: 1 b: 2 c: 3 d: 4 e: 5 }
服务器的传输返回的只能是 string 类型的数据,可是用户若是经过 jQuery 的 dataType 定义了 json 的格式后,会默认把数据转换成 Object 的形式返回,这就是 jQuery 内部作的智能处理了,jQuery 内把自定义的 dataType 与服务器返回的数据作相对应的映射处理,经过 converters 存储对应的处理句柄,把须要类型转换器 ajaxConvert 在服务端响应成功后,对定义在 jQuery. ajaxSettings 中的 converters 进行遍历,找到与数据类型相匹配的转换函数,并执行。
converters的映射
converters: { // Convert anything to text、 // 任意内容转换为字符串 // window.String 将会在min文件中被压缩为 a.String "* text": window.String, // Text to html (true = no transformation) // 文本转换为HTML(true表示不须要转换,直接返回) "text html": true, // Evaluate text as a json expression // 文本转换为JSON "text json": jQuery.parseJSON, // Parse text as xml // 文本转换为XML "text xml": jQuery.parseXML }
除此以外还有额外扩展的一部分 jsonp 的处理,因此其格式就是。
text –> (html,json,script)的处理了
其寓意就是服务器返回的用于只是 string 类型的文本格式,须要转化成用户想要的 dataType 类型的数据:
{"* text": window.String, "text html": true, "text json": jQuery.parseJSON, "text xml": jQuery.parseXML}
类型的转化都是发生在服务器返回数据后,因此对应的就是 ajax 方法中的 done 以后,固然这个 done 方法也是通过请求分发器包装过的,至于为何要这样处理,上章就已经提到过了,为了处理正常请求与 jsonp 的跨域请求的问题。
因此当 AJAX 请求完成后,会调用闭包函数 done,在 done 中判断本次请求是否成功,若是成功就调用 ajaxConvert 对响应的数据进行类型转换。
因此在此以前须要:
1. 正确分配 dataType 类型,若是用户不设置(空)的状况 2. 须要转化成 converters 映射表对应的格式好比(* text, text html , text xml , text json)
dataType 类型的转化
dataType 类型的参数,能够是 xml, json, script, or html 或者干脆为空,那么 jQuery 就须要一个方法去判断当前是属于什么数据处理,就此引入了 ajaxConvert 处理响应转化器,解析出正确的 dataType 类。
response = ajaxConvert(s, response, jqXHR, isSuccess);
分析下 dataType 没法就那么几种状况
1. dataType 为空,自动转化
此时 jQuery 只能根据头部信息来猜想当前须要处理的类型,删除掉通配 dataType,获得返回的 Content-Type。
while (dataTypes[0] === "*") { dataTypes.shift(); if (ct === undefined) { ct = s.mimeType || jqXHR.getResponseHeader("Content-Type"); } }
经过 xhr.getAllResponseHeaders() 获得头部信息,而后去匹配 Content-Type 全部对象的值便可,固然找到这个 Content-Type = “html”,咱们还得看看有没有对应处理的方法,若是有就须要替换这个 dataTypes。
看看是否是咱们能处理的 Content-Type,好比图片这类二进制类型就很差处理了。
if (ct) { // 实际上能处理的就是text、xml和json for (type in contents) { if (contents[type] && contents[type].test(ct)) { dataTypes.unshift(type); break; } } }
通过这个流程后,dataTypes 原本是 * 就变成了对应的 html了,这是 jquery 内部的自动转化过。
2. dataType开发者指定
xml, json, script, html, jsop类型转换器将服务端响应的 responseText 或 responseXML,转换为请求时指定的数据类型 dataType,若是没有指定类型就依据响应头 Content-Type 自动处理。
类型转换器的执行过程
response = ajaxConvert(s, response, jqXHR, isSuccess);
流程
1.遍历dataTypes中对应的处理规则【"script","json"】 2.制做jqXHR对象的返回数据接口 json: "responseJSON" text: "responseText" xml: "responseXML" 如:jqXHR.responseText: "{"a":1,"b":2,"c":3,"d":4,"e":5}" 3.生成转化器对应的匹配规则,寻找合适的处理器 4.返回处理后的数据response
分析一下特殊的 jsonp 的转化流程,先看看转化对应的处理器。
jsonp
converters["script json"] = function() { if (!responseContainer) { jQuery.error(callbackName + " was not called"); } return responseContainer[0]; };
jsonp 的转化器只是很简单的从 responseContainer 取出了对应的值,因此 responseContainer 确定在转化以后就应该把数据给转化成数组对象了,固然作源码分析须要一点本身猜测能力,好比 responseContainer 这个数组对象如何而来?
那么咱们知道 jsonp 的处理的原理,仍是经过加载 script,而后服务器返回一个回调函数,responseContainer 数据就是回调函数的实参,因此须要知足 responseContainer 的处理,必需要先知足脚本先加载,因此咱们要去分发器中找对应的加载代码,首先responseContainer 是内部变量,只有一个来源处,在预处理的时候增长一个全局的临时函数,而后代码确定是执行了这个函数才能把 arguments 参数赋给 responseContainer。
overwritten = window[callbackName]; window[callbackName] = function() { responseContainer = arguments; }; //callbcakName是内部建立的一个尼玛函数名 jQuery203029543792246840894_1403062512436 = function() { responseContainer = arguments; };
咱们发送请求:
http://192.168.1.114/yii/demos/test.php?backfunc=jQuery203029543792246840894_1403062512436&action=aaron&_=1403062601515
服务器那边就回调后,执行了 jQuery203029543792246840894_1403062512436(responseContainer ) 因此全局的 callbackName 函数须要在分发器中脚本加载后才能执行,从而才能截取到服务器返回的数据。