保存到桌面加入收藏设为首页
java开发
当前位置:首页 > java开发

jQuery.Deferred 源码分析-安度博客

时间:2019-02-04 14:53:06   作者:   来源:   阅读:110   评论:0
内容摘要:作者:禅楼望月( http://www.cnblogs.com/yaoyinglong )1 引子视察者模式是我们日常开发中经常用的模式。这个模式由两个主要部门组成:宣布者和视察者。通过视察者模式,实现宣布者和视察者的解耦。宣布者主要认真宣布内容,视察者主要认真监听宣布者宣布的内......
  • 作者:禅楼望月( http://www.cnblogs.com/yaoyinglong )

    1 引子

    视察者模式是我们日常开发中经常用的模式。这个模式由两个主要部门组成:宣布者和视察者。通过视察者模式,实现宣布者和视察者的解耦。

    宣布者主要认真宣布内容,视察者主要认真监听宣布者宣布的内容,并作出相应的行动。和我们平时订阅期刊一样,cnki会维护一个订阅者列表,有期刊被宣布出来时,cnki会将这些期刊推送给订阅者。从法式角度来说,订阅者就是一堆的要领,宣布者的推送内容的行动就是依次调用订阅者列表中的要领(订阅者),而宣布的内容就将以参数的形式提供应订阅者。

    image

    在jQuery中Deferred就是用来实现这一模式的。

    我们首先来一个简朴的订阅与宣布示例:

    [+]view code  

    word-break: normal; margin: 0cm 0cm 0pt; line-height: 21.6pt; text-indent: 0pt; mso-pagination: widow-orphan;">//建设一个宣布者

    word-break: normal; margin: 0cm 0cm 0pt; line-height: 21.6pt; text-indent: 0pt; mso-pagination: widow-orphan;">var subject=$.Deferred();

    //建设两个订阅者

    function subscriber1(content){

        console.log(content);

    }

    function subscriber2(content){

        console.log(content);

    }

    //订阅内容

    subject.done(subscriber1subscriber2);

    //宣布内容

    subject.resolve('谢谢你的订阅');

    image

    下面我们来分析,$.Deferred的源码,在这个历程中,我们还会$.Deferred的种种使用情况。

    2 构建Deferred

    首先我们将Deferred源码做简化处置惩罚:

    image

    其中,tuples是一种数据结构。它是一种很是巧妙的设计,是把有共性的代码合并到一起,然后一次性举行处置惩罚。promise是deferred的一种简化形式(去掉了改变状态的接口)。Deferred是一个工厂类,返回的是内部建设好的deferred工具。

    [+]view code   var tuples =[
      // action add listener listener list final state
      //once 体现resolve和reject只要触发过一次,后面就不能再被触发了
      ['resolve''done' jQuery.Callbacks('once memory')'resolved']
      ['reject''fail' jQuery.Callbacks('once memory')'rejected']
      ['notify''progress' jQuery.Callbacks('memory')]
    ]

    tuples界说3中状态的,即resolve,reject,notify。这三种状态划分对应了3中订阅接口(done,fail,progress)和3种订阅列表(3个Callbacks),resolve和reject有最终的状态(resolved和rejected)。下面就是为找这个数据结构,来构建带这3中状态的Deferred。

    首先界说了初始状态:state = 'pending'

    然后构建promise工具:

    image

    在构建deferred工具:

    image

    构建deferred分为2步:

    1. 构建3种状态对应的接口,订阅者列表,和推送内容接口。

    构建订阅者列表,3430行,列表由一个Callbacks来治理,其实整个Deferred就是基于Callbacks来实现的,把它们的代码放在一起对比,会发现出奇的相似,构建状态字符串(划分为resolved、rejected或者undefined)。

    $.each执行完会有3个列表生成:

    doneList=$.Callbacks('once memory');
    failList=$.Callbacks('once memory');
    progressList=jQuery.Callbacks('memory');

    界说订阅接口3434行,他们就是订阅列表(Callbacks)的add要领。add进去的订阅者会存储在Callbacks的list数组中。

    3中订阅接口划分为:

    promise.done=doneList.add;
    promise.fail=failList.add;
    promise.progress=progressList.add

    为resolved和rejected两种状态的列表添加预设的3个回调函数(3437~3444)。第一个回调函数用于处置惩罚Deferred的状态(已乐成或已失败),第二个回调函数用于让另一个列表失效,这是因为当宣布者宣布内容的行动已经乐成了,它就不行能再触发失败的状态,因此让失败列表失效,防止给正在订阅了失败状态的函数被执行。反之亦然。然后锁定notify列表。锁定notify只是让其的progressList的fire要领(即后面不能使用notify和notifyWith再举行推送内容了)不能被调用了。可是,我们还可以给notify状态继续添加订阅者,这些订阅者会连忙被执行。

    这里有个小技巧:i^1,^是按位运算符

    image

    没什么大用,可是jQuery就是要连这点性能也要节约出来。

    至此,doneList的list中有3个回调函数[changeState failList.disable progressList.lock]failList的list中同样有3个回调函数[changeState doneList.disable progressList.lock]

    构建推送内容接口(3447~3451),三种接口名字划分为

    deferred.resolve(乐成),deferred.reject(失败),deferred.notify(正在执行),这三个接口在内部其实又去调用这三个接口对应的带参数版本(deferred.resolveWith,deferred.rejectWith,deferred.notifyWith),而三个接口又是订阅列表(Callbacks)的fireWith要领。由此可见,要能很是明确的看懂Deferred的源码,必须对Callbacks的源码很是熟悉,至少要能熟练运用Callbacks。

    2. 将deferred的精简版promise中的要领和属性或从到自己身上。(3455)这里的promise也是一种很是巧妙的处置惩罚。

    结构竣事后我们就会获得如下图所示的Deferred工具:

    image

    至此,Deferred工具构建完成。

    较量发现,promise比deferred少了6个内容推送功效。没有了这几个功效deferred的状态也就不会被改变。

    3 Deferred的使用

    3.1 done,resolve; fail,reject; progress,notify

    [+]view code var def=$.Deferred();
    setTimeout(function () {
    console.log('耗时操作……');
    def.resolve('本次推送的内容……');
    }1000);
    def.done(function () {
    console.log(arguments[0]);
    });

    image

    这个历程很是简朴,只是对Callbacks的简朴包装。

    [+]view code

    var def=$.Deferred();
    setTimeout(function () {
      new Error('欠盛情思,堕落了……');
      def.reject('台风影响,本次推送堕落……');
    }1000);
    def.done(function () {
      console.log(arguments[0]);
    }).fail(function () {
      console.log(arguments[0]);
    });

    这里的原理和是谁人面的一模一样。

    [+]view code

    var def=$.Deferred();
    setTimeout(function() {
        console.log('正在执行……');
        def.notify('正在执行……');
    }1000);
    def.done(function () {
        console.log(arguments[0]);
    }).fail(function () {
        console.log(arguments[0]);
    }).progress(function() {
        console.log(arguments[0]);
    });

    3.2 then()

    [+]view code

    var def=$.Deferred();
    setTimeout(function () {
        console.log('正在执行……');
        def.notify('正在执行……');
    }1000);
    def.then(function () {
        console.log(arguments[0]);
    }function () {
        console.log(arguments[0]);
    }function () {
        console.log(arguments[0]);
    });

    image

    then要领返回一个新的的Deferred工具的精简版promise。在建设该Deferred是通报进去了一个function参数。我们发现,在构建Deferred的工厂要领就有一个func参数,它内部的处置惩罚是这样的:

    image

    以工厂要领建设的deferred为上下文,以该deferred为参数来调用这个要领。函数执行完后,工厂要领将deferred返回。

    然后我们来看这个func详细是怎么设计的,这里的设计的很是之庞大。这里最重要的看法就是作用域链,如果对这些基础知识不熟悉的话,明确起来真的很费劲……

    image

    以上面实例代码为例,来分析then的源码:

    image

    分析源码不仅可以回首javascript知识,还可以借鉴别人的设计思路,代码书写方式,对提高自身的修养是很有资助的。

    下一章分析jQuery.when的实现……


最近更新

精彩推荐

阅读排行

本站所有站内信息仅供娱乐参考,不作任何商业用途,不以营利为目的,专注分享快乐,欢迎收藏本站!
所有信息均来自:百度一下 (威尼斯人官网)