jQuery源码分析系列(36) : Ajax - 类型转化器
什么是类型转化器?
jQuery支持不同格式的数据返回形式,比如dataType为 xml, json,jsonp,script, or html
但是浏览器的XMLHttpRequest对象对数据的响应只有 responseText与responseXML 二种
所以现在我要定义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的处理
// Ajax请求设置默认的值
jQuery.ajaxSetup({
/**
* 内容类型发送请求头(Content-Type),用于通知服务器该请求需要接收何种类型的返回结果。
* 如果accepts设置需要修改,推荐在$.ajaxSetup() 方法中设置一次。
* @type {Object}
*/
accepts: {
script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
},
contents: {
script: /(?:java|ecma)script/
},
converters: {
"text script": function(text) {
jQuery.globalEval(text);
return text;
}
}
});
所以其格式就是
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就需要一个只能的方法去判断当前是属于什么数据处理
因此就引入了
ajaxHandleResponses 处理响应转化器,解析出正确的dataType类型
response = ajaxHandleResponses(s, jqXHR, responses);
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);
源码部分
function ajaxConvert(s, response, jqXHR, isSuccess) {
current = dataTypes.shift();
while (current) {
if (current) {
// 如果碰到了*号,即一个任意类型,而转换为任意类型*没有意义
if (current === "*") {
current = prev;
// 转化的重点
// 如果不是任意的类型,并且找到了一个不同的类型
} else if (prev !== "*" && prev !== current) {
// Seek a direct converter
// 组成映射格式,匹配转化器
// * text: function String() { [native code] }
// script json: function () {
// text html: true
// text json: function parse() { [native code] }
// text script: function (text) {
// text xml: function (data) {
conv = converters[prev + " " + current] || converters["* " + current];
// If none found, seek a pair
// 假如找不到转化器
// jsonp是有浏览器执行的呢,还是要调用globalEval
if (!conv) {
//...............
}
// Apply converter (if not an equivalence)
// 如果有对应的处理句柄,执行转化
if (conv !== true) {
// Unless errors are allowed to bubble, catch and return them
if (conv && s["throws"]) {
response = conv(response);
} else {
try {
//执行对应的处理句柄,传入服务器返回的数据
response = conv(response);
} catch (e) {
return {
state: "parsererror",
error: conv ? e : "No conversion from " + prev + " to " + current
};
}
}
}
}
}
}
return {
state: "success",
data: response
};
}
流程
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函数需要在分发器中脚本加载后才能执行,从而才能截取到服务器返回的数据
我也不可能每个都分析到位,所以大家有选择的自己根据需求去看源码吧,大体的流程思路理解的,看起来就很快了,至于其余的类型,在之后遇到了就会在分析了
jQuery源码分析系列(36) : Ajax - 类型转化器的更多相关文章
- jQuery源码分析系列(37) : Ajax 总结
综合前面的分析,我们总结如下3大块: jQuery1.5以后,AJAX模块提供了三个新的方法用于管理.扩展AJAX请求 前置过滤器 jQuery. ajaxPrefilter 请求分发器 jQuery ...
- 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 ...
随机推荐
- [R]R语言中的%>%和%.%
最近在网上看R的代码,常常看到 x %>% y 的写法. 样子看着像是pipe的用法,搜了一下, 没找到语法的相关说明. 今天突然开窍,想着 %>% 可能不是语言本身支持的语法,可能是某个 ...
- 全本软件白名单 Quanben Software Whitelist
Windows应用软件 Windows Applications (TBU) 全本推荐微软Windows 10操作系统 Quanben recommends Microsoft Windows 10 ...
- 浅谈ajax
Ajax 回顾 最本质的 ajax 其实是这样的: function Ajax(){ var xmlHttpReq = null; if (window.ActiveXObject){//IE5 IE ...
- 文档ID:某某 模板文件不存在,无法解析文档!
如果是生成栏目列表时出现这样的问题]: 1.可以修改include/arc.listview.class.php这个文件. 2.复制代码 echo "模板文件不存在,无法解析文档 ...
- centos7 解决ftp和apache运行目录权限冲突问题
1.将ftp用户加入到apache用户组 usermod -a -G apache ftpadmin ftpadmin 为ftp用户 2.设置网站根目录/var/www的所有组为apache chow ...
- WEB前端工程师(实践)制作天气预报难度:简单
需要准备:jQuery Bootstrap 天气预报API(本文中使用API可能会失效请灵活运用) CSS样式可以你自己去写这里只提出jQuery 请求数据和解析JSON数据 { "resu ...
- java排序学习笔记
前面写了js的排序实现,总得玩玩java的哈. 同样,冒泡.选择.快速(这三个之前实现过也写过文章).堆排序,然后做比较. 主要遇到的难点: - -||想轻松点写个封装计时的逻辑,不想每调用一个排序就 ...
- ThreadPoolExecutor源码学习(2)-- 在thrift中的应用
thrift作为一个从底到上除去业务逻辑代码,可以生成多种语言客户端以及服务器代码,涵盖了网络,IO,进程,线程管理的框架,着实庞大,不过它层次清晰,4层每层解决不同的问题,可以按需取用,相当方便. ...
- Call to undefined function Think\mb_strlen()
在php.ini 中开启php_mbstring.dll 模块后重启 apache
- 初识 Html5
1.1认识HTML5 HTML5并不仅仅只是做为HTML标记语言的一个最新版本,更重要的是它制定了Web应用开发的一系列标准,成为第一个将Web做为应用开发平台的HTML语言. HTML5定义了一系列 ...