(本文针对jQuery1.6.1版本号)关于Deferred函数的描写叙述中有一个词是fledged,意为"羽翼丰满的",说明jQuery.Deferred函数应用应该更成熟。

这个函数与jQuery._Deferred函数有密不可分的关系。

1 内部实现

	Deferred: function( func ) {
var deferred = jQuery._Deferred(),
failDeferred = jQuery._Deferred(),
promise;
// Add errorDeferred methods, then and promise
jQuery.extend( deferred, {
then: function( doneCallbacks, failCallbacks ) {
deferred.done( doneCallbacks ).fail( failCallbacks );
return this;
},
always: function() {
return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
},
fail: failDeferred.done,
rejectWith: failDeferred.resolveWith,
reject: failDeferred.resolve,
isRejected: failDeferred.isResolved,
pipe: function( fnDone, fnFail ) {
return jQuery.Deferred(function( newDefer ) {
jQuery.each( {
done: [ fnDone, "resolve" ],
fail: [ fnFail, "reject" ]
}, function( handler, data ) {
var fn = data[ 0 ],
action = data[ 1 ],
returned;
if ( jQuery.isFunction( fn ) ) {
deferred[ handler ](function() {
returned = fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise().then( newDefer.resolve, newDefer.reject );
} else {
newDefer[ action ]( returned );
}
});
} else {
deferred[ handler ]( newDefer[ action ] );
}
});
}).promise();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
if ( obj == null ) {
if ( promise ) {
return promise;
}
promise = obj = {};
}
var i = promiseMethods.length;
while( i-- ) {
obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
}
return obj;
}
});
// Make sure only one callback list will be used
deferred.done( failDeferred.cancel ).fail( deferred.cancel );
// Unexpose cancel
delete deferred.cancel;
// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}
return deferred;
},

事实上一张图就能非常好的说明调用jQuery.Deferred()函数之后返回的对象内部结构。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

调用jQuery.Deferred()函数返回的也是一个异步对象,可是这个异步对象相比較jQuery._Deferred()返回对象是属于增强型的。这个增强的异步对象在内部很巧妙的使用了两个普通异步对象deferred和failDeferred,之所以不叫两个"异步队列",是由于那样会简单化这两个异步对象的真实结构--它们根本就不是一种数据结构,而是一系列特殊数据(闭包中的四个变量)和操作(五个方法)的集合,上一篇已具体展开描写叙述过。



这两个异步对象在jQuery.Deferred函数内初始化的时候全然同样:分别调用了一次jQuery._Deferred()函数而获得两个新创建的独立的异步对象,事实上这个时候它们并没有地位上的差异,就像一对孪生兄弟一样--身高一致。体重一致。可是接下来就厚此薄彼了--仅仅对当中一个对象deferred扩展属于还有一个对象failDeferred中的属性。扩展属性的一方deferred成为大哥。被共享属性免费提供服务的一方failDeferred成为小弟。

函数最后返回的引用仅仅有大哥deferred,大哥出人头地了。小弟被成为踏脚石永远暗无天日了(因为有大哥对他属性的引用。自己主动垃圾回收收不走他,真是想shi都无门的弟弟)。

从外部使用的角度看,仅仅有一个增强型异步对象deferred。可是这个对象具备了两个弹夹、两个扳机,这在实际生活中貌似还没有哪位设计师实现过这种武器(具有双管的枪型倒有不少),未来单兵武器系统--枪榴弹与袭击步枪合二为一的模型与此有部分相似。



通过扩展一套对立的操作增强一个普通异步对象到增强型异步对象的目的是添加很多其它的回调钩子应对很多其它的场景。这里通过第二个普通异步对象扩展了一套reject操作。其实,我们当然能够添加很多其它的普通异步对象扩展很多其它的操作,比方1.7版本号后又引入一套progess操作以说明场景不是仅仅有成功和失败,还有处理中呢。



Deferred函数内部运行了这样一句代码"deferred.done( failDeferred.cancel ).fail( deferred.cancel );",给增强的异步对象deferred提前提供两颗子弹,且这两个函数各自是兄弟俩的cancel函数,这将会达到一个相互排斥的效果--当调用方内部运行成功时能够触发射击deferred的弹夹callbacks,这个弹夹中的第一颗子弹(callbacks.shift())就是failDeferred对象的cancel方法,击发这颗子弹就锁死failDeferred对象了(failDeferred弹夹的其它子弹将不能被击发了);当调用方内部运行失败时能够触发射击failDeferred的弹夹callbacks,这个弹夹中的第一颗子弹(callbacks.shift())就是deferred对象的cancel方法,击发这颗子弹就锁死deferred对象了(deferred弹夹的其它子弹将不能被击发了)。之所以不说"一定"而是用"能够"这样的描写叙述,是由于两个弹夹能够互换使用的,仅仅是约定failDeferred对象的弹夹装失败场景下的触发函数集而已。



对增强型异步对象的扩展到这里貌似已经完美了,该有的很多其它的回调钩子都有了,可是等等,想想还有没有其它问题?第一篇文章讲过,普通异步对象的五个方法中有一个全能保险:cancelled和cancel方法,调用cancel方法后整个异步对象彻底锁死不能工作了。而增强型异步对象尽管没有引用弟弟的cancel操作,可是自己本身也有这种方法。所以为了避免让调用方任意关闭这个保险。jQuery从返回的哥哥对象中删除这个操作了"delete deferred.cancel;",这又相当于对哥哥的弱化处理(不能给它太多特权)。尽管外部不能调用这个操作了,可是增强型异步对象已经预先将cancel操作作为两颗子弹压入到弹仓了,这就是上一段代码的作用,另一个基础事实是删除的仅仅是引用,并没有删除cancel方法本身。



上面分析的都是jQuery.Deferred()这样的调用,这个函数也能够接受一个函数參数,这个參数函数仅仅被传入一个參数--增强的异步对象自身,至于函数内部怎么处理增强异步对象,全然由调用方自主决策--给了调用方在使用这把枪之前依据自己的喜好先设置一下它的机会,比方典型的初始化(能够在这里装入子弹)等,反正调用方已不能关闭它的保险了。

2 对jQuery._Deferred()扩展的promise()函数

这种方法须要单独讲讲。

前面说过对增强型异步对象有扩展增强也有收缩减弱。这个状态的增强型异步对象功能已经是完备的了。用于jQuery内部其它模块已经没有问题了。可是假设把这个异步对象直接交给不熟悉手枪操作的用户还是可能会引起误操作--尽管用户无法关闭保险,可是可能会在不恰当的时机运行"开枪射击"的操作(调用resolveWith方法或rejectWith方法)。射击的触发时机通常是有严格约束的。它往往与详细情境有关,比方浏览器载入dom仅仅有全然完毕时才干够触发相关指定事件运行,所以为了防止用户在错误的时间运行错误的事件,能够约束用户仅仅要他提供详细的回调函数就可以。实际的触发操作由jQuery自己决定,这样提供给用户的异步对象就不能有"开枪"的操作。为了实现这个目的,在增强型异步对象上扩展了一个promise方法,调用该方法返回增强型异步对象的一个傀儡,而不是增强型异步对象本身,这个傀儡仅仅同意下面操作集:'promiseMethods
= "done fail isResolved isRejected promise then always pipe".split( " " )'。因为傀儡相应操作引用指向增强型异步对象相应同样的操作方法,所以设置这个傀儡的回调函数的同一时候对原增强型异步对象的回调函数的设置同一时候生效。



当然promise方法也能够接受一个參数。提供这个參数的话就把相关设置方法赋给这个參数对象,而不是给傀儡了。

补充一句,熟悉设计模式的同学一定能准确说出promise方法使用的是什么设计模式。

3 对jQuery._Deferred()扩展的pipe()函数

这个pipe方法是很挑战智力的一个方法。真正的"asynchronize"这个概念的实现就足够先进了(想想java中从bio到nio花了几个版本号和多长时间。从nio到aio又花了几个版本号和多长时间),再加上"pipe"这个概念也不是那么easy的(參照netty pipeline),所以彻底理解这种方法是相当费脑细胞的,因为兴许1.7以后的版本号中这种方法过时了,这里就不展开分析了。



最后总结一下,第一篇通过"手枪"模型详解了jQuery._Deferred函数的内部原理,本篇通过"未来单兵武器系统"模型详解jQuery.Deferred函数的内部原理,能够看到增强型异步对象本身并没有引入其它过多复杂的机制,仅仅是通过增强或减弱普通异步对象的功能来达到设计的目的。因此重点还是jQuery._Deferred函数。另外增强型异步对象尽管攻克了"添加很多其它的回调钩子应对不同场景下的回调逻辑"这个需求,可是jQuery整个异步机制还缺少最后一个环节--"什么时候由谁开枪"。更通俗的说是怎么应用于实际场景中。这个主题在下一篇解说jQuery.when函数时展开(上面对promise方法的解析中提到过一部分)。

最后再次郑重申明:本系列文章未经许可,严禁转载。

jQuery异步框架探究2:jQuery.Deferred方法的更多相关文章

  1. jQuery异步框架探究1:jQuery._Deferred方法

    jQuery异步框架应用于jQuery数据缓存模块.jQuery ajax模块.jQuery事件绑定模块等多个模块,是jQuery的基础功能之中的一个.实际上jQuery实现的异步回调机制能够看做ja ...

  2. jQuery原生框架中的jQuery.fn.extend和jQuery.extend

    extend 方法在 jQuery 中是一个很重要的方法,jQuey 内部用它来扩展静态方法或实例方法,而且我们开发 jQuery 插件开发的时候也会用到它.但是在内部,是存在 jQuery.fn.e ...

  3. jQuery UI框架

    jQuery UI框架 1.oschina开源社区-jQuery教程 2.jQuery PrimeUI(推荐) 3.弹出框.警告框.提示框.拖动支持.位置固定.选项卡切换 4.Bootstrap框架( ...

  4. jQuery验证框架 .

          目录视图 摘要视图 订阅 “程序人生”中国软件开发者职业生涯调查     CSDN社区“三八节”特别活动      开发者职业生涯调查之未来 jQuery验证框架 分类: JQuery 2 ...

  5. jquery ajax异步提交表单数据的方法

    使用jquery的ajax方法可以异步提交表单,成功后后台返回json数据,回调函数处理,可以不用刷新页面,达到异步的目的: 处理表单的数据可以用serialize()方法进行序列化,而如果提交的数据 ...

  6. jquery源码解析:jQuery延迟对象Deferred(工具方法)详解2

    请接着上一课继续看. $.Deferred()方法中,有两个对象,一个是deferred对象,一个是promise对象. promise对象有以下几个方法:state,always,then,prom ...

  7. JS常用方法总结,及jquery异步调用后台方法实例

    //前台接收get参数值 function getQueryString(name) {            var queryStrings = window.location.search.sp ...

  8. jQuery源代码框架思路

    開始计划时间读源代码,第一节jQuery框架阅读思路整理 (function(){ jQuery = function(){}; jQuery一些变量和函数和给jQuery对象加入一些方法和属性 ex ...

  9. 使用反射机制实现jQuery调用ashx类中的指定方法

    使用反射机制实现jQuery调用ashx类中的指定方法   近期用asp.net做个小网站,但又不喜欢使用asp.net的服务器端控件,经过一番思量后确定前端采用原始的html.后台采用Linq to ...

随机推荐

  1. [LeetCode] Search for a Range 二分搜索

    Given a sorted array of integers, find the starting and ending position of a given target value. You ...

  2. (二十二)函数fseek() 用法

    fseek 函数名: fseek功 能: 重定位流上的文件指针用 法: int fseek(FILE *stream, long offset, int fromwhere);描 述: 函数设置文件指 ...

  3. ajax验证前端页面

    1.html页面 用ajax验证表单的时候不需要form标签,并把提交按钮由type=“submit ”改为type=“button” 数据表结构 ajax.html <!DOCTYPE htm ...

  4. 安全提示“X-Frame-Options头未设置”的解决方法

    漏洞检测提示“X-Frame-Options头未设置”,意思是网页可能被别人用iframe框架使用.事实上,我的网页已经通过js程序禁止被iframe框架嵌入使用了.不过,对于使用iis的网站来说,可 ...

  5. cordova学习:事件Events

    deviceready: 当cordova完全加载,可以调用cordova API接口 支持平台:Amazon.Fire OS.Android.BlackBerry 10.iOS.Tizen.Wind ...

  6. 正则表达式之Regex.Replace()用法

    正则表达式替换匹配到的字符串 string txt = "AAA12345678AAAA"; //匹配到的连续数字的前4位用*替换 string m =Regex.Replace( ...

  7. OpenJDK中java.lang.NoClassDefFoundError: com/sun/image/codec/jpeg/ImageFormatException解决办法

    http://www.cnblogs.com/xusweeter/p/9667801.html

  8. [jquery] 给动态生成的元素绑定事件 on方法

    用底下的方法尝试了好多次都失败 $('.del').on('click',function(){ alert('aa'); })// 失败!! 终于在准备放弃前看到一篇博文说的方法 $(documen ...

  9. 深入分析CVE-2016-5195 Dirty Cow

    前面一段时间,这个编号为CVE-2016-5195的漏洞刷爆了各个安全相关的博客和网站,这个漏洞可以对任意可读文件进行写操作从而导致提权,通杀了包括Android在内的绝大多数linux版本,,影响不 ...

  10. Map泛型集合-显示企鹅信息

    package collection; /** * 宠物类 * @author * */ public class Pet { private String name; private String ...