开发者社区> 文艺小青年> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

jQuery源码分析系列(31) : Ajax deferred实现

简介:
+关注继续查看

AJAX的底层实现都是浏览器提供的,所以任何基于api上面的框架或者库,都只是说对于功能的灵活与兼容维护性做出最优的扩展

ajax请求的流程:

1、通过 new XMLHttpRequest 或其它的形式(指IE)生成ajax的对象xhr。  

2、通过xhr.open(type, url, async, username, password)的形式建立一个连接。 

3、通过setRequestHeader设定xhr的请求头部(request header)。  

4、通过send(data)请求服务器端的数据。

5、执行在xhr上注册的onreadystatechange回调处理返回数据。

这几步之中,

我们开发者可能会遇到的问题

1 跨域

2 json的格式

3 dataType

4 AJAX乱码问题

5 页面缓存

6 状态的跟踪

7 不同平台兼容

jQuery主要就是解决上面这问题,之后就在这个基础之上进行扩展

 


jQuery2.0.3版的Ajax部分源码大概有1200多行,主要针对ajax的操作进行了一些扩展,使之更加灵活

jQuery在1.5中对AJAX模块的重写,增加了几个新的概念

AJAX模块提供了三个新的方法用于管理、扩展AJAX请求,分别是:

  • 前置过滤器 jQuery. ajaxPrefilter
  • 请求分发器 jQuery. ajaxTransport,
  • 类型转换器 ajaxConvert

除此之后还重写了整个异步队列处理,加入了deferred,可以将任务完成的处理方式与任务本身解耦合,使用deferreds对象,多个回调函数可以被绑定在任务完成时执行,甚至可以在任务完成后绑定这些回调函数。这些任务可以是异步的,也可以是同步的。

比如

1.链式反馈done与fail

复制代码
$.ajax({
    url: "script.php",
    type: "POST",
    data: {
        id: menuId
    },
    dataType: "html"
}).done(function(msg) {
    $("#log").html(msg);
}).fail(function(jqXHR, textStatus) {
    alert("Request failed: " + textStatus);
});
复制代码

 

2.分离异步与同步处理

复制代码
var aajax = $.ajax({
    url: "script.php",
    type: "POST",
    data: {
        id: menuId
    },
    dataType: "html"
}).fail(function(jqXHR, textStatus) {
    alert("Request failed: " + textStatus);
});


//同步还在执行代码,这个函数有可能在AJAX结束前调用
dosomething()

//异步还在等在成功响应
aajax.done(function(msg) {
    $("#log").html(msg);
})
复制代码

不再被限制到只有一个成功,失败或者完成的回调函数了。相反这些随时被添加的回调函数被放置在一个先进先出的队列中。

 

3.同时执行多个ajax请求

复制代码
function ajax1() {
    return $.get('1.htm');
}

function ajax2() {
    return $.get('2.htm');
}


$.when(ajax1(), ajax2())
    .then(function() {
       //成功
    })
    .fail(function() {
       //失败
    });
复制代码

这个比较复杂一点,原理其实就是$.get返回的是一个deferred对象,每个jQuery的AJAX方法返回值都包含一个promise函数,用来跟踪异步请求。Promise函数的返回值是deferred对象的一个只读视图

Deferreds通过检测对象中是否存在promise()函数来判断当前对象是否可观察。$.when()会等待所有的AJAX请求结束,然后调用通过 .then(), .fail()注册的回调函数(具体调用哪些回调函数取决于任务的结束状态)。这些回调函数会按照他们的注册顺序执行

显而易见,deferred对象就是jQuery的回调函数解决方案,它解决了如何处理耗时操作的问题,对那些操作提供了更好的控制,以及统一的编程接口

 


jqXHR 对象

说白了无非就是在ajax的实现逻辑中,把deferred对象给掺进去了,使之整个ajax方法变成了一个deferred对象

在ajax方法中返回的是jqXHR一个包装对象,在这个对象里面混入了所有实现方法

ajax: function(url, options) {
    //.........
    return jqXHR
}

从jQuery 1.5开始$.ajax() 返回XMLHttpRequest(jqXHR)对象,该对象是浏览器的原生的XMLHttpRequest对象的一个超集。例如,它包含responseTextresponseXML属性,以及一个getResponseHeader()方法。当传输机制不是是XMLHttpRequest时(例如,一个JSONP请求脚本,返回一个脚本 tag 时),jqXHR对象尽可能的模拟原生的XHR功能。

从jQuery 1.5.1开始, jqXHR对象还包含了overrideMimeType方法 (它在jQuery 1.4.x中是有效的,但是在jQuery 1.5中暂时的被移除)。.overrideMimeType() 方法可能用在beforeSend()的回调函数中,例如,修改响应的Content-Type信息头:

为了让回调函数的名字统一,便于在$.ajax()中使用。jqXHR也提供.error() .success().complete()方法。这些方法都带有一个参数,该参数是一个函数,此函数在 $.ajax()请求结束时被调用,并且这个函数接收的参数,与调用 $.ajax()函数时的参数是一致。这将允许你在一次请求时,对多个回调函数进行赋值,甚至允许你在请求已经完成后,对回调函数进行赋值(如果该请求已经完成,则回调函数会被立刻调用)。

为了向后兼容XMLHttpRequest ,一jqXHR对象将公开下列属性和方法:

  • readyState
  • status
  • statusText
  • responseXML and/or responseText 当底层的请求分别作出XML和/或文本响应
  • setRequestHeader(name, value) 从标准出发,通过替换旧的值为新的值,而不是替换的新值到旧值
  • getAllResponseHeaders()
  • getResponseHeader()
  • abort()

image

 


那么在对包装器jqXHR对象做混入之前,我们要先准备好

1 异步队列deferred

2 回调队列Callbacks

复制代码
// Deferreds
deferred = jQuery.Deferred(),

/**
 * 所有的回调队列,不管任何时候增加的回调保证只触发一次
 * @type {[type]}
 */
completeDeferred = jQuery.Callbacks("once memory"),
复制代码

 

给jqXHR扩充添加promise的属性和方法,然后添加complete方法,这里用的是回调列表的add方法(即添加回调)

deferred.promise(jqXHR).complete = completeDeferred.add;

image

此时的jqXHR就具有了promise的一些特性了与callback的回调列队了

当然这里有个重点,返回了一个只读的deferred对象

如果返回完整的deferred对象,那么外部程序就能随意的触发deferred对象的回调函数,很有可能在AJAX请求结束前就触发了回调函数(resolve),这就是与AJAX本身的逻辑相违背了。

所以为了避免不经意间改变任务的内部流程,我们应该只返回deferred的只读版本 deferred.promise()

然后把对应的done与fail改成别名success与error

jqXHR.success = jqXHR.done;
jqXHR.error   = jqXHR.fail;

 

 

image

 

我们还需要把用户自定的内部回调函数给注册到jqXHR对象上

复制代码
// 增加回调队列
        for (i in {
            success  : 1,
            error    : 1,
            complete : 1
        }) {
            /**
             * 把参数的回调函数注册到内部jqXHR对象上,实现统一调用
             * 给ajax对象注册 回调函数add
             * deferred返回complete,error外部捕获
             */
            jqXHR[i](s[i]);
        }
复制代码

jqXHR.success(s.success)  -> jqXHR.done -> jQuery.Callbacks("once memory")

jqXHR.error(s.error)  -> jqXHR.fail -> jQuery.Callbacks("once memory")

jqXHR.complete(s.complete) -> jQuery.Callbacks("once memory").add(s.success)

待续....


本文转自艾伦 Aaron博客园博客,原文链接:http://www.cnblogs.com/aaronjs/p/3713016.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
JQuery实现仿sina新浪微博新鲜事滚动
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.
666 0
过去几个月出炉的30款最喜欢的 jQuery 插件
  在这篇文章中,我们收集了一些在过去的几个月里最喜欢的 jQuery 插件。为了使您更容易搜索到自己喜欢的 jQuery 插件,我们已经对插件进行了分类: 页面布局插件,图片和视频插件,滑块和画廊,排版插件等等。
952 0
Web 开发最有用的50款 jQuery 插件集锦——《内容滑块篇》
  今天给大家带来的是在 Web 项目中常用的内容滑块插件。这个系列的文章将向大家分享50款最具创新的,同时也是最有用的 jQuery 插件,这些插件分成以下类别:网页布局插件,导航插件,表格插件,滑块和转盘插件,图表插件,图片特效插件以及视频插件等等,欢迎大家关注我的后续博文。
1261 0
Swipebox – 用于触屏设备的精美 jQuery Lightbox 插件
  Swipebox 是一款可触摸的 jQuery 灯箱效果插件,可用于桌面,移动和平板电脑。它移动设备支持滑动手势导航,桌面电脑上可以用键盘导航,不支持 CSS3 过渡特性的浏览器使用 jQuery 降级处理,支持视网膜显示,能够通过 CSS 轻松定制。
885 0
Unslider – 轻量的响应式 jQuery 内容滑块插件
  Unslider 是一款非常轻量的 jQuery 插件(压缩后只有 1KB),能够用于任何 HTML 内容的滑动。可以响应容器的大小变化,自动排布不用大小的滑块。可以通过整合 jQuery.event.swipe 来让其支持触屏设备的滑动功能。
972 0
jPanelMenu – 创建面板风格菜单的 jQuery 插件
  jPanelMenu 是一款用于创建面板风格的 jQuery 菜单插件。这种风格在移动版的 Facebook 和 Google 以及众多的原生 iPhone 应用中很常见。在支持的设备上使用硬件加速的 CSS3 过渡来实现平滑的动画效果,对于支持的浏览器,使用 jQuery 动画引擎作为降级方案。
799 0
Spoiler Alert – 实现内容模糊隐藏效果的 jQuery 插件
  Spoiler Alert 是一款非常好玩的 jQuery 小插件,可以在您的网站上实现内容模糊隐藏效果。鼠标悬停的时候会有提示,点击一下就可以看到原始的内容了。   我能想到的最好的应用场景是在线测验,先把答案隐藏,等答完题后点击可以核对答案。
872 0
2012年最有用的50款 jQuery 插件集锦——《表单篇》
  这篇文章继续向大家分享一批实用的 jQuery 插件,今天带来的是网站项目中最常用的表单插件。这是一个系列的文章,将向大家分享50款最具创新的,同时也是最有用的 jQuery 插件,这些插件分成以下类别:网页布局插件,导航插件,表格插件,滑块和转盘插件,图表插件,图片特效插件以及视频插件等等,欢迎大家关注。
1020 0
【精心推荐】20款优秀 jQuery Accordion(手风琴)特效插件
  Accordion(手风琴)是网站中常用的效果之一,用于一组内容(图片、文本等)之间的切换显示。使用 jQuery 能够轻松实现 Accordion 效果,今天这篇文章向大家推荐网站开发中常用的20款优秀 jQuery 手风琴效果插件。
1528 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
JavaScript异步编程
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载