jQuery1.9.1源码分析系列(十六)ajax之ajax框架


Posted in Javascript onDecember 04, 2015

AJAX 简介

AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

您应当具备的基础知识

在继续学习之前,您需要对下面的知识有基本的了解:

HTML / XHTML
CSS
JavaScript / DOM

如果您希望首先学习这些项目,请在我们的首页访问这些教程。

什么是 AJAX ?

AJAX = 异步 JavaScript 和 XML。

AJAX 是一种用于创建快速动态网页的技术。

通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。

有很多使用 AJAX 的应用程序案例:新浪微博、Google 地图、开心网等等。

Google Suggest

在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。

Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。

今天就开始使用 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, "+" );
};

其中encodeURIComponent详细点击查看

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;
Javascript 相关文章推荐
javascript replace方法与正则表达式
Feb 19 Javascript
JS类的封装及实现代码
Dec 02 Javascript
poshytip 基于jquery的 插件 主要用于显示微博人的图像和鼠标提示等
Oct 12 Javascript
JavaScript判断DOM何时加载完毕的技巧
Nov 11 Javascript
javascript限制用户只能输汉字中文的方法
Nov 20 Javascript
Node.js实现批量去除BOM文件头
Dec 20 Javascript
JavaScript判断一个字符串是否包含指定子字符串的方法
Mar 18 Javascript
js中Number数字数值运算后值不对的解决方法
Feb 28 Javascript
Node.js 使用命令行工具检查更新
Jun 08 Javascript
微信小程序使用modal组件弹出对话框功能示例
Nov 29 Javascript
create-react-app中添加less支持的实现
Nov 15 Javascript
浅析JavaScript预编译和暗示全局变量
Sep 03 Javascript
jQuery使用$.ajax进行异步刷新的方法(附demo下载)
Dec 04 #Javascript
Jquery1.9.1源码分析系列(十五)动画处理之外篇
Dec 04 #Javascript
写给小白的JavaScript引擎指南
Dec 04 #Javascript
jQuery实现ajax调用WCF服务的方法(附带demo下载)
Dec 04 #Javascript
jQuery旋转木马式幻灯片轮播特效
Dec 04 #Javascript
jQuery中cookie插件用法实例分析
Dec 04 #Javascript
JavaScript截取指定长度字符串点击可以展开全部代码
Dec 04 #Javascript
You might like
推荐一篇入门级的Class文章
2007/03/19 PHP
window+nginx+php环境配置 附配置搭配说明
2010/12/29 PHP
PHP中SESSION使用中的一点经验总结
2012/03/30 PHP
基于PHP读取csv文件内容的详解
2013/06/18 PHP
50个PHP程序性能优化的方法
2014/06/02 PHP
PHP连接MYSQL数据库实例代码
2016/01/20 PHP
php验证身份证号码正确性的函数
2016/07/20 PHP
PHP实现一个轻量级容器的方法
2019/01/28 PHP
PHP实现的权重算法示例【可用于游戏根据权限来随机物品】
2019/02/15 PHP
javascript 当前日期转化为中文的实现代码
2010/05/13 Javascript
jQuery Mobile页面跳转后未加载外部JS原因分析及解决
2013/03/18 Javascript
js实现漂浮回顶部按钮实例
2015/05/06 Javascript
深入浅出分析javaScript中this用法
2015/05/09 Javascript
jquery实现可自动判断位置的弹出层效果代码
2015/10/12 Javascript
html+javascript+bootstrap实现层级多选框全层全选和多选功能
2017/03/09 Javascript
webpack+vue中使用别名路径引用静态图片地址
2017/11/20 Javascript
jquery实现弹窗(系统提示框)效果
2019/12/10 jQuery
小程序使用分包的示例代码
2020/03/23 Javascript
Python multiprocessing.Manager介绍和实例(进程间共享数据)
2014/11/21 Python
python: 判断tuple、list、dict是否为空的方法
2018/10/22 Python
Python实现批量修改图片格式和大小的方法【opencv库与PIL库】
2018/12/03 Python
Python制作exe文件简单流程
2019/01/24 Python
scrapy-redis的安装部署步骤讲解
2019/02/27 Python
Form表单及django的form表单的补充
2019/07/25 Python
Python list与NumPy array 区分详解
2019/11/06 Python
Java文件与类动手动脑实例详解
2019/11/10 Python
python图片验证码识别最新模块muggle_ocr的示例代码
2020/07/03 Python
Python绘图之二维图与三维图详解
2020/08/04 Python
美国最大的旗帜经销商:Carrot-Top
2018/02/26 全球购物
俄罗斯家居用品购物网站:Евродом
2020/11/21 全球购物
计算机专业应届毕业生自荐信
2013/09/26 职场文书
检讨书格式
2019/04/25 职场文书
一行代码python实现文件共享服务器
2021/04/22 Python
Pandas 稀疏数据结构的实现
2021/07/25 Python
Mysql事务索引知识汇总
2022/03/17 MySQL
《辉夜大小姐想让我告白》第三季正式预告
2022/03/20 日漫