jQuery-1.9.1源码分析系列(十六)ajax——ajax框架
既然是ajax框架,那么闲谈一谈jQuery的ajax处理思路。
现在的浏览器都支持ajax,只不过不同的浏览器使用方法可能有不同(IE使用new window.ActiveXObject("Microsoft.XMLHTTP"),标准浏览器使用new window.XMLHttpRequest())。如果按照这种思路,貌似jQajax只需要做好兼容处理就行了?
不是的,原生的ajax有一个说大不大说小不小的缺点——不支持跨域(同源策略由来已久,自行百度)。所以jQajax添加了这方面的处理,jQajax是如何解决跨域问题的?
<img src="http://img2.imgtn.bdimg.com/it/u=2406301718,2822592556&fm=21&gp=0.jpg"/>
是能取到图片的,很明显图片的路径和你的服务端不是一个域的。你可以试试看所有的带有src属性的标签都不受同源策略的影响。所以,jQuery就使用了这个属性,对于跨域请求使用script标签的src来请求路径。
然后jQuery在加上对ajax事件的三种监听方式:
1.全局事件:$(document).on(‘ajaxStart’,func);
2.ajax设置回调项:$.ajax({url: "php.html", complete: func });
3.deferred绑定方式:$.ajax(…).done(func);
基本上这就是jQajax所做的事情。
在正真进入ajax框架核心之前,先来分析一jQuery准备的几个序列化提交表单的函数。
a. 表单序列化
所谓的表单序列化即将表单需要提交的内容组成类似:“key=value&key=value…”形式的字符串。
序列化用到三个函数:
jQuery.fn. serialize()(序列化函数,筛选出表单中需要提交的数据并以序列化字符串方式返回,形如:“key=value&key=value…”)
jQuery.fn. serializeArray()(筛选出表单中需要提交的数据并以key/value键值对的对象数组格式返回,返回[{name:’key’,value:’select1’},{name:’selectM’,value:’selectM1’}, {name:’selectM’,value:’selectM2’}, { name:’key2’,value:0}…])
jQuery.param(serializeArray, traditional )(将key/value键值对的对象数组序列化为“key=value&key=value…”字符串)。
serialize直接调用jQuery.param( this.serializeArray() )即可。
serializeArray的源码如下:主要进行三个步骤:提取表单元素、过滤出满足提交条件的表单元素、组合成key/value键值对的对象数组
serializeArray: function() {
//将form中的表单相关的元素取出来组成数组
return this.map(function(){
//表单节点有elements这个特征
var elements = jQuery.prop( this, "elements" );
return elements ? jQuery.makeArray( elements ) : this;
})
//过滤出为需要提交的表单元素(有name名称、非disabled元素、非提交按钮等元素、checkbox/radio的checked的元素)
.filter(function(){
var type = this.type;
//使用.is(":disabled")过滤掉不可用的表单元素
return this.name && !jQuery( this ).is( ":disabled" ) &&
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
( this.checked || !manipulation_rcheckableType.test( type ) );
})
//将表单提交元素组成name和value的对象数组
.map(function( i, elem ){
var val = jQuery( this ).val();
return val == null ?
null :
jQuery.isArray( val ) ?
jQuery.map( val, function( val ){
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
}) :
{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
}).get();
}
需要注意的是jQuery的过滤结果符合正常的表单提交结果://过滤出为需要提交的表单元素(有name名称、非disabled元素、非提交按钮等元素、checkbox/radio的checked的元素)
param函数源码如下:主要进行两个处理:将key/value成作为URI组件编码(保证key和value不会出现特殊符号,即保证了“=”分割的正确性)、使用“&”链接并将空白符被替换成了"+"
jQuery.param = function( a, traditional ) {
var prefix,
s = [],
add = function( key, value ) {
//如果value是函数,执行他得到真正的value
value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
//把key和value作为URI组件编码,保证key和value不会出现特殊符号,即保证了“=”分割的正确性
s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
};
...
//传入的是数组,假设他是一个form表单键值对数组
if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
//序列化表单元素
jQuery.each( a, function() {
add( this.name, this.value );
});
} else {
...
}
//返回序列化结果,注意:空白符被替换成了"+"
return s.join( "&" ).replace( r20, "+" );
};
b. ajax的事件监听
给ajax绑定事件有三种方式
1.全局事件:$(document).on(‘ajaxStart’,func);
2.ajax设置回调项:$.ajax({url: "php.html", complete: func });
3.deferred绑定方式:$.ajax(…).done(func);
接下来我们一一讲解他们的实现。
全局事件(ajaxStart/ajaxStop/ajaxComplete/ajaxError/ajaxSuccess/ajaxSend)
使用.on事件绑定这种通用方式我们毫无疑问是可以绑定ajax监听事件,除此之外还可以直接使用$(…).ajaxStart(func)来绑定事件。他们的实现也是用.on来绑定。
jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
jQuery.fn[ type ] = function( fn ){
return this.on( type, fn );
};
});
触发事件比较简单,在进行ajax处理过程中在合适的时机直接使用jQuery.event.trigger直接触发。以ajaxStart为例
//如果此时没有正在执行的请求,则触发ajaxStart事件
if ( fireGlobals && jQuery.active++ === 0 ) {
jQuery.event.trigger("ajaxStart");
}
ajax设置回调项(beforeSend/complete/success/error)
触发设置回调项分两种:beforeSend直接在适当的时机调用。源码
//调用beforeSend回调,如果回调返回失败或abort则返回中止
if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
//中止如果没有准备好
return jqXHR.abort();
}
complete/success/error则利用Deferred的特性将回调添加到延时队列,等待延时状态处理。源码
//创建最终选项对象
s = jQuery.ajaxSetup( {}, options )
...
deferred = jQuery.Deferred(),
completeDeferred = jQuery.Callbacks("once memory"),
... //添加延时事件
deferred.promise( jqXHR ).complete = completeDeferred.add;
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail; //安装回调到deferreds上
for ( i in { success: 1, error: 1, complete: 1 } ) {
jqXHR[ i ]( s[ i ] );
} //在ajax请求完成的处理函数中执行completeDeferred的延时列表
function done(){
...
//执行Complete处理
completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
...
}
deferred方式绑定回调
Deferred方式绑定事件就不用特别说明了,因为ajax本身就是一个延时对象。直接使用$.ajax(…).done(fn).fail(fn). progress(fn).always(fn).then(fn)。源码
deferred = jQuery.Deferred(),
completeDeferred = jQuery.Callbacks("once memory"),
...
deferred.promise( jqXHR ).complete = completeDeferred.add;
...
return jqXHR;
如果觉得本文不错,请点击右下方【推荐】!
jQuery-1.9.1源码分析系列(十六)ajax——ajax框架的更多相关文章
- ABP源码分析二十六:核心框架中的一些其他功能
本文是ABP核心项目源码分析的最后一篇,介绍一些前面遗漏的功能 AbpSession AbpSession: 目前这个和CLR的Session没有什么直接的联系.当然可以自定义的去实现IAbpSess ...
- ABP源码分析三十六:ABP.Web.Api
这里的内容和ABP 动态webapi没有关系.除了动态webapi,ABP必然是支持使用传统的webApi.ABP.Web.Api模块中实现了一些同意的基础功能,以方便我们创建和使用asp.net w ...
- ABP源码分析四十六:ABP ZERO中的Ldap模块
通过AD作为用户认证的数据源.整个管理用户认证逻辑就在LdapAuthenticationSource类中实现. LdapSettingProvider:定义LDAP的setting和提供Defaut ...
- Android源码分析(十六)----adb shell 命令进行OTA升级
一: 进入shell命令界面 adb shell 二:创建目录/cache/recovery mkdir /cache/recovery 如果系统中已有此目录,则会提示已存在. 三: 修改文件夹权限 ...
- spark 源码分析之十六 -- Spark内存存储剖析
上篇spark 源码分析之十五 -- Spark内存管理剖析 讲解了Spark的内存管理机制,主要是MemoryManager的内容.跟Spark的内存管理机制最密切相关的就是内存存储,本篇文章主要介 ...
- jQuery-1.9.1源码分析系列(六) 延时对象应用——jQuery.ready
还记不记得jQuery初始化函数jQuery.fn.init中有这样是一个分支 //document ready简便写法$(function(){…}) } else if ( jQuery.isFu ...
- Vue.js 源码分析(二十六) 高级应用 作用域插槽 详解
普通的插槽里面的数据是在父组件里定义的,而作用域插槽里的数据是在子组件定义的. 有时候作用域插槽很有用,比如使用Element-ui表格自定义模板时就用到了作用域插槽,Element-ui定义了每个单 ...
- jQuery-1.9.1源码分析系列(六) 延时对象续——辅助函数jQuery.when
$.when的说明 描述: 提供一种方法来执行一个或多个对象的回调函数,返回这些对象的延时(Deferred)对象. 说明(结合实例和源码): 如果你不传递任何参数, jQuery.when()将返 ...
- jQuery-1.9.1源码分析系列(六) 延时对象
首先我们需要明白延时对象有什么用? 第一个作用,解决时序以及动态添加执行函数的问题. function a(){alert(1)}; function b(){alert(2)}; function ...
- Spring源码分析(十六)准备创建bean
本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 我们不可能指望在一个函数中完成一个复杂的逻辑,而且我们跟踪了这么多Spring ...
随机推荐
- Unity小游戏制作 - 暗影随行
用Unity制作小游戏 - 暗影惊吓 最近玩了一个小游戏,叫做暗影惊吓,虽然是一个十分简单的小游戏,但是感觉还是十分有趣的.这里就用Unity来实现一个类似的游戏. 项目源码:DarkFollow 主 ...
- JAVA的continue用法
JAVA的continue用法: public class test{ public static void main(String [] args){ for(int i=0;i<=10;i ...
- eclipse配置javah命令
1.找到javah命令所在的目录 我的为 /usr/bin/javah 2.打开eclipse 如图点击第二项 3.配置 如图 ${project_loc}/src -classpat ...
- 架构之路(七)MVC点滴
我们目前正在开发中的是任务管理系统,一个前端复杂的项目,所以我们先从MVC讲起吧. WebForm 随着ASP.NET MVC的兴起,WebForm已成昨日黄花,但我其实还很想为WebForm说几句. ...
- 自己动手写一个简单的MVC框架(第二版)
一.ASP.NET MVC核心机制回顾 在ASP.NET MVC中,最核心的当属“路由系统”,而路由系统的核心则源于一个强大的System.Web.Routing.dll组件. 在这个System.W ...
- ASP.Net MVC开发基础学习笔记:二、HtmlHelper与扩展方法
一.一个功能强大的页面开发辅助类—HtmlHelper初步了解 1.1 有失必有得 在ASP.Net MVC中微软并没有提供类似服务器端控件那种开发方式,毕竟微软的MVC就是传统的请求处理响应的回归. ...
- PHP制作查询租房表
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 浅谈android中的目录结构
之前在android游戏开发中就遇到本地数据存储的问题:一般情形之下就将动态数据写入SD中存储,在没有SD卡的手机上就需另作处理了;再有在开发android应用的过程中,总要去调试APP,安装时又想去 ...
- JS数组定义及详解
1.什么是数组 数组就是一组数据的集合 其表现形式就是内存中的一段连续的内存地址 数组名称其实就是连续内存地址的首地址 2.关于js中的数组特点 数组定义时无需指定数据类型 数组定义时可以无需指定数组 ...
- WPF入门教程系列十七——WPF中的数据绑定(三)
四. XML数据绑定 这次我们来学习新的绑定知识,XML数据绑定.XmlDataProvider 用来绑定 XML 数据,该XML数据可以是嵌入.Xmal文件的 XmlDataProvider 标记中 ...