- 浏览: 522044 次
- 性别:
- 来自: 北京
博客专栏
-
jQuery技术内幕
浏览量:201231
最新评论
-
青春依旧:
学习html5哪里好?当然华清远见是首选!
[原创] jQuery源码分析-01总体架构 -
追梦1819:
[size=x-small][color=red][/colo ...
[原创] jQuery源码分析-04 选择器-Sizzle-设计思路 -
niuqiang2008:
学习学习
[原创] jQuery源码分析-04 选择器-Sizzle-工作原理 -
liuweihug:
jquery 解析正则表达式及常见的Regex规则和表达式 - ...
[原创] jQuery源码分析-02正则表达式-RegExp-常用正则表达式 -
liang8768:
mark!!!
[原创] jQuery源码分析-00前言开光
作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com
声明:本文为原创文章,如需转载,请注明来源并保留原文链接。
边读边写,不对的地方请告诉我,多多交流共同进步,PDF下载在最后
jQuery源码分析系列的目录请查看 http://nuysoft.iteye.com/blog/1177451,想系统的好好写写,目前还是从我感兴趣的部分开始,如果大家有对哪个模块感兴趣的,建议优先分析的,可以告诉我,一起学习。
15.5 AJAX中的类型转换器
前置过滤器、 请求分发器、类型转换器是读懂jQuery AJAX实现的关键,可能最难读的又是类型转换器。除此之外的源码虽然同样的让人纠结,但相较而言并不算复杂。
类型转换器将服务端响应的responseText或responseXML,转换为请求时指定的数据类型dataType,如果没有指定类型就依据响应头Content-Type自动猜测一个。在分析转换过程之前,很有必要先看看类型转换器的初始化过程,看看支持哪些类型之间的转换。
15.5.1 类型转换器的初始化
类型转换器ajaxConvert在服务端响应成功后,对定义在jQuery. ajaxSettings中的converters进行遍历,找到与数据类型相匹配的转换函数,并执行。我们先看看converters的初始化过程,对类型类型转换器的功能有个初步的认识。jQuery. ajaxSettings定义了所有AJAX请求的默认参数,我们暂时先忽略其他属性、方法的定义和实现:
jQuery.extend({ // some code ... // ajax请求的默认参数 ajaxSettings: { // some code ...
// List of data converters // 1) key format is "source_type destination_type" (a single space in-between) // 2) the catchall symbol "*" can be used for source_type // 类型转换映射,key格式为单个空格分割的字符串:源格式 目标格式 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 } } // some code ... }); |
然后在jQuery初始化过程中,对jQuery. ajaxSettings.converters做了扩展,增加了text>script的转换:
// Install script dataType // 初始化script对应的数据类型 // MARK:AJAX模块初始化 jQuery.ajaxSetup({ accepts: { script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" }, contents: { script: /javascript|ecmascript/ }, // 初始化类型转换器,这个为什么不写在jQuery.ajaxSettings中而要用扩展的方式添加呢? // 这个转换器是用来出特殊处理JSONP请求的,显然,jQuery的作者John Resig,时时刻刻都认为JSONP和跨域要特殊处理! converters: { "text script": function( text ) { jQuery.globalEval( text ); return text; } } }); |
初始化过程到这里就结束了,很简单,就是填充jQuery. ajaxSettings.converters。
当一个AJAX请求完成后,会调用闭包函数done,在done中判断本次请求是否成功,如果成功就调用ajaxConvert对响应的数据进行类型转换(闭包函数done在讲到jQuery.ajax()时一并分析):
// 服务器响应完毕之后的回调函数,done将复杂的善后事宜封装了起来,执行的动作包括: // 清除本次请求用到的变量、解析状态码&状态描述、执行异步回调函数队列、执行complete队列、触发全局Ajax事件 // status: -1 没有找到请求分发器 function done( status, statusText, responses, headers ) { // 省略代码... // If successful, handle type chaining // 如果成功的话,处理类型 if ( status >= 200 && status < 300 || status === 304 ) { // 如果没有修改,修改状态数据,设置成功 if ( status === 304 ) { 省略代码... } else {
try { // 获取相应的数据 // 在ajaxConvert这个函数中,将Server返回的的数据进行相应的转换(js、json等等) success = ajaxConvert( s, response ); // 注意:这里的succes变为转换后的数据对象! statusText = "success"; isSuccess = true; } catch(e) { // We have a parsererror // 数据类型转换器解析时出现错误 statusText = "parsererror"; error = e; } } // 非200~300,非304 } else { // We extract error from statusText // then normalize statusText and status for non-aborts // 其他的异常状态,格式化statusText、status,不采用HTTP标准状态码和状态描述 error = statusText; if( !statusText || status ) { statusText = "error"; if ( status < 0 ) { status = 0; } } } // 省略代码... } |
15.5.2 类型转换器的执行过程
类型转换器ajaxConvert根据请求时设置的数据类型,从jQuery. ajaxSettings.converters寻找对应的转换函数,寻找的过程非常绕。假设有类型A数据和类型B数据,A要转换为B(A > B),首先在converters中查找能 A > B 对应的转换函数,如果没有找到,则采用曲线救国的路线,寻找类型C,使得类型A数据可以转换为类型C数据,类型C数据再转换为类型B数据,最终实现 A > B。类型转换器的原理并不复杂,复杂的是它的实现:
// Chain conversions given the request and the original response // 转换器,内部函数,之所以不添加到jQuery中,可能是因为这个函数不需要客户端显示调用吧 function ajaxConvert( s, response ) {
// Apply the dataFilter if provided // dataFilter也是一个过滤器,在调用时的参数options中设置,在类型类型转换器执行之前调用 if ( s.dataFilter ) { response = s.dataFilter( response, s.dataType ); }
var dataTypes = s.dataTypes, // 取出来,减少作用域查找,缩短后边的拼写 converters = {}, i, key, length = dataTypes.length, tmp, // Current and previous dataTypes current = dataTypes[ 0 ], // 取出第一个作为起始转换类型 prev, // 每次记录前一个类型,以便数组中相邻两个类型能形成链条 // Conversion expression conversion, // 类型转换表达式 被转换类型>目标了类型 // Conversion function conv, // 从jQuery.ajaxSetting.converts中取到特定类型之间转换的函数 // Conversion functions (transitive conversion) conv1, // 两个临时表达式 conv2;
// For each dataType in the chain // 从第2个元素开始顺序向后遍历,挨着的两个元素组成一个转换表达式,形成一个转换链条 for( i = 1; i < length; i++ ) {
// Create converters map // with lowercased keys // 将s.converters复制到converters,为什么要遍历转换呢?直接拿过来用不可以么? if ( i === 1 ) { for( key in s.converters ) { if( typeof key === "string" ) { converters[ key.toLowerCase() ] = s.converters[ key ]; } } }
// Get the dataTypes prev = current; // 取出前一个类型,每次遍历都会把上一次循环时的类型记录下来 current = dataTypes[ i ]; // 取出当前的类型
// If current is auto dataType, update it to prev if( current === "*" ) { // 如果碰到了*号,即一个任意类型,而转换为任意类型*没有意义 current = prev; // 所以回到前一个,跳过任意类型,继续遍历s.dataTypes // If no auto and dataTypes are actually different // 这里开始才是函数ajaxConvert的重点 // 前一个不是任意类型*,并且找到了一个不同的类型(注意这里隐藏的逻辑:如果第1个元素是*,跳过,再加上中间遇到的*都被跳过了,所以结论就是s.dataTypes中的*都会被忽略!) } else if ( prev !== "*" && prev !== current ) {
// Get the converter 找到类型转换表达式对应的转化函数 conversion = prev + " " + current; // 合体,组成类型转换表达式 conv = converters[ conversion ] || converters[ "* " + current ]; // 如果没有对应的,就默认被转换类型为*
// If there is no direct converter, search transitively // 如果没有找到转变表达式,则向后查找 // 因为:jsonp是有浏览器执行的呢,还是要调用globalEval呢? if ( !conv ) { // 如果没有对应的转换函数,则寻找中间路线 conv2 = undefined; // for( conv1 in converters ) { // 其实是遍历s.converts tmp = conv1.split( " " ); // 将s.convsert中的类型转换表达式拆分,tmp[0] 源类型 tmp[1] 目标类型 // 如果tmp[0]与前一个类型相等,或者tmp[0]是*(*完全是死马当作活马医,没办法的办法) if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) { // 这里的*号与conv=这条语句对应 // 形成新的类型转换表达式, 看到这里,我有个设想,简单点说就是: // A>B行不通,如果A>C行得通,C>B也行得通,那么A>B也行的通:A > C > B // 将这个过程与代码结合起来,转函数用fun(?>?)表示: // A == tmp[0] == prev // C == tmp[1] // B == current // conv1 == A>C conv2 = converters[ tmp[1] + " " + current ]; // 看看C>B转换函数有木有,conv==fun(C>B) if ( conv2 ) { // 如果fun(C>B)有,Great!看来有戏,因为发现了新的类型转换表达式A>C>B conv1 = converters[ conv1 ]; // conv1是A>C,将A>C转换函数取出来,conv1由A>C变成fun(A>C) if ( conv1 === true ) { // true是什么东西呢?参看jQuery.ajaxSettings知道 "text html": true,意思是不需要转换,直接那来用 conv = conv2; // conv2==fun(C>B),赋给conv,conv由func(A>B)变成fun(C>B) // 详细分析一下: // 这里A==text,C==html,B是未知,发现A>B行不通,A>C和C>B都行得通, // 但是因为A>C即text>html不需要额外的转换可以直接使用,可以理解为A==C,所以可以忽略A>C,将A>C>B链条简化为C>B // 结果就变成这样: A>C>B链条中的A>C被省略,表达式简化为C>B // 如果conv1不是text>html,即A!=C,那么就麻烦了,但是,又发现conv2即fun(C>B)是text>html,C==B,那么A>C>B链条简化为A>C } else if ( conv2 === true ) { // conv2==func(C>B) conv = conv1; // A>C>B链条简化为A>C } /** * 将上边与代码紧密结合的注释再精炼: * 目标是A>B但是行不通,但是A>C可以,C>B可以,表达式变成A>C>B * 如果A=C,表达式变成C>B,上边的conv2 * 如果C=B,表达式变成A>C,上边的conv1 */ /** * 但是要注意,到这里还没完,如果既不是A==C,也不是C==B,表达式A>C>B就不能简化了! * 怎么办?虽然到这里conv依然是undefined,但是知道了一条A通往B的路,剩下的工作在函数ajaxConvert的最后完成! */ break; // 找到一条路就赶紧跑,别再转悠了
} } } } // If we found no converter, dispatch an error // 如果A>B行不通,A>?>B也行不通,?表示中间路线,看来此路是真心不通啊,抛出异常 if ( !( conv || conv2 ) ) { // 如果conv,conv2都为空 jQuery.error( "No conversion from " + conversion.replace(" "," to ") ); } // If found converter is not an equivalence // 如果找到的conv是一个函数或者是undefined if ( conv !== true ) { // Convert with 1 or 2 converters accordingly // 分析下边的代码之前,我们先描述一下这行代码的运行环境,看看这些变量分别代表什么含义: // 1. conv可能是函数表示A>B可以 // 2. conv可能是undefined表示A>B不可以,但是A>C>B可以 // 3. conv1是fun(A>C),表示A>C可以 // 4. conv2是fun(C>B),表示C>B可以
// 那么这行代码的含义就是: // 如果conv是函数,执行conv( response ) // 如果conv是undefined,那么先执行conv1(response),即A>C,再执行conv2( C ),即C>B,最终完成A>C>B的转换 response = conv ? conv( response ) : conv2( conv1(response) ); } } } return response; } |
ajaxConvert的源码分析让我破费一番脑筋,因为它的很多逻辑没有显示的体现在代码上,是隐式的。我不敢对这样的编程方式妄下定论,也许这样的代码不易维护,也许仅仅是我的水平还不够。
15.5.3 总结
通过前面的源码解析,可以将类型转换器总结如下:
属性 |
值 |
功能 |
* text |
window.String |
任意内容转换为字符串 |
text html |
true |
文本转换为HTML(true表示不需要转换,直接返回) |
text json |
jQuery.parseJSON |
文本转换为JSON |
text script |
function( text ) { jQuery.globalEval( text ); return text; } |
用eval执行text |
text xml |
jQuery.parseXML |
文本转换为XML |
如果在上表示中没有找到对应的转换函数(类型A > 类型B),就再次遍历上表,寻找新的类型C,使得可以 A > C > B。
后记:
到此,最关键的前置过滤器、请求分发器、类型转换器已经分析完毕,但是AJAX实现的复杂度还是远远超过了我最初的认识,还有很多地方值得深入学习和分析,比如:jQuery.ajax的实现、数据的解析、异步队列在AJAX中的应用、多个内部回调函数调用链、jqXHR的状态码与HTTP状态码的关系、数据类型的修正、跨域、对缓存的修正、对HTTP状态码的修正,等等等等,每一部分都可以单独成文,因此对AJAX的分析还会继续。提高自己的同时,希望对读者有所启发和帮助。
- _原创__jQuery源码分析-15AJAX-类型转换器.pdf (385.6 KB)
- 下载次数: 49
发表评论
-
[原创] jQuery源码分析-04 选择器-Sizzle-设计思路
2011-11-14 20:59 6879作者:nuysoft/高云 QQ:47214707 Em ... -
[原创] jQuery源码分析-04 选择器-Sizzle-工作原理
2011-11-13 23:45 7915作者:nuysoft/高云 QQ:47214707 EM ... -
[原创] jQuery源码分析-02正则表达式-RegExp-常用正则表达式
2011-10-27 01:29 46680作者:nuysoft/JS攻城师/ ... -
[原创] jQuery源码分析-jQuery中的循环技巧
2011-10-27 00:36 14578作者:nuysoft/JS攻城师/高云 QQ:47214707 ... -
[原创] jQuery源码分析-10事件处理-Event-DOM-ready
2011-10-20 01:20 10631作者:nuysoft/JS攻城师/ ... -
[原创] jQuery源码分析-Java工程师应该向jQuery学习的8点建议
2011-10-18 23:56 12279作者:nuysoft/高云 QQ:47214707 EM ... -
[原创] jQuery源码分析-10事件处理-Event-事件绑定与删除-bind/unbind+live/die+delegat/undelegate
2011-10-18 22:31 15700作者:nuysoft/高云 QQ:47214707 EM ... -
[原创] jQuery源码分析-10事件处理-Event-源码结构
2011-10-17 01:01 12152作者:nuysoft/高云 QQ:47214707 EMail ... -
[原创] jQuery源码分析-07数据缓存-Cache
2011-10-13 19:55 12173作者:nuysoft/高云 QQ:47214707 EMail ... -
[原创] jQuery源码分析-06浏览器测试-Support
2011-10-13 19:19 9956作者:nuysoft/高云 QQ:47214707 EMail ... -
[原创] jQuery源码分析系列目录(持续更新)
2011-10-12 12:30 29406作者:nuysoft/高云 QQ:47214707 E ... -
[原创] jQuery源码分析-10事件处理-Event-概述和基础知识
2011-10-12 00:16 12044作者:nuysoft/高云 Q ... -
[原创] jQuery源码分析-08队列 Queue
2011-10-10 23:48 10838作者:nuysoft/高云 Q ... -
[原创] jQuery源码分析-03构造jQuery对象-工具函数
2011-09-29 23:21 29822作者:nuysoft/高云 QQ:47214707 E ... -
[原创] jQuery源码分析-03构造jQuery对象-源码结构和核心函数
2011-09-28 02:20 53017作者:nuysoft/高云 QQ:47214707 EMail ... -
[原创] jQuery源码分析-如何做jQuery源码分析
2011-09-27 00:22 15030近期在ITEYE陆续写了几篇jQuery源码分析,乐在其 ... -
[原创] jQuery源码分析-17尺寸和大小 Dimensions & Offset
2011-09-25 22:05 7077边读边写,不正确的地方,还请各位告诉我,多多交流共同学习, ... -
[原创] jQuery源码分析-15AJAX-前置过滤器和请求分发器
2011-09-23 00:09 13314边读边写,不正确的 ... -
[原创] jQuery源码分析-00前言开光
2011-09-21 23:42 47041jQuery源码分析 - 前言 jQuery凭借简洁的语法和 ... -
[原创] jQuery源码分析-01总体架构
2011-09-21 23:31 751661. 总体架构 1.1 自调用匿名函 ...
相关推荐
- **类型转换器**:探讨jQuery中的类型转换机制,即如何将服务器返回的不同格式的数据转换为JavaScript可以处理的对象。 #### 六、动画与视觉效果 - **动画分析和扩展Effects**:研究jQuery中动画实现的底层逻辑,...
### jQuery源码分析关键知识点详解 #### 一、前言 在深入了解jQuery源码之前,有必要先简要介绍一下jQuery的基本情况及其对JavaScript编程领域的重要意义。jQuery作为一个轻量级、功能丰富的JavaScript库,在Web...
深入理解jQuery源码有助于开发者更好地利用其API并优化性能。主要关注点包括: 1. **选择器引擎(Sizzle)**:jQuery 使用Sizzle作为其选择器引擎,它是如何快速高效地解析CSS选择器并找到匹配元素的。 2. **链式...
### JQuery源码的奥秘逐行分析视频教程 #### JQuery简介 JQuery 是一款轻量级的 JavaScript 库,它极大地简化了 HTML 文档遍历、事件处理、动画以及 Ajax 交互等操作。JQuery 提供了一个简洁且强大的 API 接口,...
### jQuery源码分析系列_1.6 #### 一、前言 在现代Web开发领域,jQuery无疑是一款具有里程碑意义的JavaScript库。它通过简洁、强大的API极大地简化了DOM操作、事件处理、Ajax交互以及动画等功能,使得前端开发变得...
《jQuery 1.4.3 源码分析——核心部分》 jQuery 是一个广泛使用的JavaScript库,它极大地简化了JavaScript的DOM操作、事件处理、动画制作和Ajax交互。在jQuery 1.4.3版本中,其核心部分主要包括选择器引擎、DOM操作...
在网页开发中,jQuery是一个非常流行的JavaScript库,它极大地简化了JavaScript代码的编写,使得DOM操作、事件处理、动画设计和Ajax交互变得更加便捷。在给定的标题"JQuery--只选择年月的日期控件"中,我们讨论的是...
通过研究jQuery源码,我们可以学习到如何优化JavaScript代码、处理DOM操作、事件处理、动画效果以及Ajax交互等多个方面的技巧。 首先,jQuery的核心是选择器引擎Sizzle,它负责高效地解析和匹配CSS选择器。Sizzle...
而“jQuery颜色选择器源码”则是基于jQuery开发的一个插件,用于帮助用户在网页中方便地选取颜色。这个源码提供了一个图形化的界面,使得用户可以通过视觉方式来挑选颜色,常应用于网页设计、表单输入或者UI组件中。...
学习和分析这个源码项目,开发者可以深入了解SSH框架和jQuery的整合应用,掌握企业级Web应用的开发流程,对于提升Java Web开发能力大有裨益。同时,对于初学者,这是一个很好的实践平台,能加深对MVC架构和前后端...
本文将深入探讨 jQuery 1.4 版本,包括其核心特性、API 使用以及源码分析。 1. **jQuery 的核心理念** - **选择器**: jQuery 提供了丰富的 CSS 选择器,使得选取 HTML 元素变得简单。例如,`$("#id")` 用于选取 ID...
### jQuery源码详细中文注释解析 #### 一、引言 jQuery作为一款优秀的JavaScript库,在前端开发领域占据着举足轻重的地位。它通过简洁的API提供了强大的DOM操作功能,极大地简化了JavaScript编程,提高了开发效率。...
源码分析可以帮助我们理解如何编写和使用jQuery插件,以及如何利用jQuery.fn.extend()来扩展jQuery对象。 7. **版本更新与优化**:随着浏览器技术的发展,jQuery也在不断进化。研究不同版本的源码差异,我们可以...
分析jQuery源码有助于理解JavaScript和DOM的交互,以及如何编写高性能、易维护的前端代码。通过深入研究,开发者可以提升自己的编程技巧,并从中吸取灵感,应用于自己的项目中。 总结,jQuery的源码不仅是前端开发...
要深入理解jQuery表单选择器的源码,可以阅读`jQuery源码`和`Sizzle源码`,同时结合实际项目进行实践。`第7章 表单选择器.pdf`文档可能是对这部分内容的一个详细讲解,建议配合源码阅读,加深理解。 总结,jQuery...
在"jQuery 分析数据统计"这个主题中,我们将深入探讨如何利用jQuery与图表库(可能是jqChart)来展示和分析数据。jqChart是jQuery的一个插件,专门用于创建各种类型的数据可视化图表,如柱状图、折线图、饼图等。 ...
这里,我们将深入探讨jQuery库的几个关键知识点,结合源码分析来增强理解。 1. **jQuery选择器**:jQuery的选择器系统是其强大功能之一,它允许开发者使用CSS1到CSS3的选择器来选取DOM元素。例如,`$("#id")`选取ID...