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

请先看上一课的回调对象。Deferred是通过extend添加到jQuery中的工具方法。如下所示:

jQuery.extend({

  Deferred: function( func ) {

  },

  when: function( subordinate /* , ..., subordinateN */ ) {

  }
});

首先,来介绍下Deferred的使用:

var cb = $.Deferred();

setTimeout(function(){

  alert(1);

  cb.resolve();

},1000)

cb.done(function(){

  alert(2);

});

以上代码执行顺序:新建一个延迟对象cb -> setTimeout,一秒后执行方法弹出1 -> 执行cb.done方法,把弹出2的方法保存 ->一秒后,执行弹出1的方法,弹出1,然后调用cb.resolve(),只要调用了cb.resolve方法,就会执行弹出2的方法。

如果大家是按照我的课程来看的话,会发现它跟Callbacks非常相似。以上代码可以用Callbacks实现:

var cb = $.Callbacks();

setTimeout(function(){

  alert(1);

  cb.fire();

},1000)

cb.add(function(){

  alert(2);

});

从上可知:$.Callbacks()  <-> $.Deferred(),cb.fire()  <-> cb.resolve();,cb.add <-> cb.done。

延迟对象主要用来处理异步的情况,比如,以上场景,要先弹出1,再弹出2,。但由于弹出1需要异步操作(比如向后台Ajax请求数据),所以需要先把弹出2的方法保存起来,等Ajax请求结束后,弹出1后,再执行弹出2的方法。当然你也可以把弹出2的方法放在setTimeout的function里面,但是这样的话,在业务逻辑复杂情况下,这个function里面的代码会非常多,不易于扩展。因此,Deferred在Ajax中用的非常多。

Deferred拥有三套处理方法集合,上面的是第一套,它代表完成,成功,触发。

第二套是:代表未完成,失败,触发

$.Callbacks()  <-> $.Deferred(),cb.fire()  <-> cb.reject();,cb.add <-> cb.fail。

第三套是:进行时,触发

$.Callbacks()  <-> $.Deferred(),cb.fire()  <-> cb.notify();,cb.add <-> cb.progress。

Deferred在Ajax中的应用举例:

当我们正常使用ajax时,是使用下面的方法操作,ajax成功就调用success方法,失败,就调用error方法。

$.ajax({

  url:"xxx.php",

  success:function(){},

  error:function(){}

})

当你使用延迟对象来操作Ajax时,只需要:done代表成功,fail代表失败

$.ajax(‘xxx.php‘).done(function(){}).fail(function(){});

调用$.ajax时,返回的是一个Deferred对象。当ajax成功时,会调用resolve方法,当失败时会调用reject方法。

接下来,分析源码:

Deferred: function( func ) {
  var tuples = [
    [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],

    //once代表只执行一次,memory代表在fire调用之后的add添加的方法也会执行(默认不会执行)。之所有这样写,是因为成功和失败只需要触发一次,而进行中,可以一直触发。
    [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
    [ "notify", "progress", jQuery.Callbacks("memory") ]
  ],

  ...... 

  jQuery.each( tuples, function( i, tuple ) {  //对数组进行遍历,tuple就是数组中的每一项(也是一个数组)
    var list = tuple[ 2 ],     //jQuery.Callbacks(),返回一个回调对象
    stateString = tuple[ 3 ];    //"resolved","rejected",undefined

    promise[ tuple[1] ] = list.add;    //回调对象的add方法。

    //tuple[1] :"done","fail","progress",用来添加方法的。promise = {"done":list.add,"fail":list.add,"progress":list.add}

    if ( stateString ) {   //tuples数组的前两项进入if语句
      list.add(function() {
          state = stateString;

        }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
    }

    deferred[ tuple[0] ] = function() {   //deferred = {"resolve":function(){会调用deferred[resolveWith](),其实就是回调对象的fireWith方法},"reject":function(){以此类推},"notify":function(){以此类推}}
      deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
      return this;
    };
    deferred[ tuple[0] + "With" ] = list.fireWith;   //回调对象的fireWith方法,其实就是fire方法,因为fire方法就是调用fireWith进行操作的
  });

  ......

}

延迟对象之所有要使用回调方法的memory参数,是因为延迟对象需要用来处理保持状态的情形,举个例子:

var cb = $.Deferred();

setTimeout(function(){

  alert(1);

  cb.resolve();

},1000)

cb.done(function(){

  alert(2);

});

$("input").click(function(){      //点击之后,立刻弹出3

  cb.done(function(){

    alert(3);

  })

})

以上代码会先弹出1,然后弹出2。之后,就停止了。只有你点击input时,才会弹出3。因为延迟对象具有记忆功能,它使用的就是具有memory参数的回调对象。当点击input时,调用延迟对象的done方法,这个done方法会再次调用resolve方法,然后进行触发,弹出3。

加油!

时间: 2024-10-19 07:52:35

jquery源码解析:jQuery延迟对象Deferred(工具方法)详解1的相关文章

jQuery 源码解析(三十一) 动画模块 便捷动画详解

jquery在$.animate()这个接口上又封装了几个API,用于进行匹配元素的便捷动画,如下: $(selector).show(speed,easing,callback)        ;如果被选元素已被隐藏,则显示这些元素 $(selector).hide(speed,easing,callback)         ;如果被选的元素已被显示,则隐藏该元素 $(selector).toggle(speed,easing,callback)     ;切换元素的可见状态,如果被选元素可

JQuery源码解析-JQuery的工具方法(3)

这篇文章主要对下面这几个方法进行解释 error();抛出异常 parseHTML():解析节点 parseJSON():解析JSON parseXML:解析XML noop():空函数 globalEval():全局解析JS camelCase():转驼峰 nodeName():是否为指定节点(内部) error:方法: error方法的作用是抛出一个自定义异常,内部直接调用了原生解释的throw new Error error: function( msg ) { throw new Err

JQuery源码解析-JQuery的工具方法(2)

这篇对下面的方法进行讲解: isFunction():是否为函数 isArray():是否为数组 isWindow():是否为window isNumeric()是否为数字 type():判断数据类型 isPlainObject():是否为对象自变量 isEmptyObject():是否为空的对象 isFunction方法: 这个方法很简单,判断对象是否为函数,返回bool类型,看一下源码: // See test/unit/core.js for details concerning isFu

JQuery源码解析-JQuery的工具方法(5)

下面对最后这几个方法进行讲解. guid():唯一表示(内部) proxy():改变this指向 access(): 多功能值操作 now():当前时间 swap():css交换(内部) guid: 这个属性是对事件进行控制的,例如每次对dom元素进行绑定事件的时候,会通过这个属性进行绑定,这个属性每次自增,产生一个唯一的标示,所以对dom元素进行事件解绑等操作的时候,通过这个属性就可以找到. 源码: // A global GUID counter for objects guid: 1, p

JQuery源码解析-JQuery的工具方法(4)

下面对这些方法进行讲解 each():遍历集合 trim():去前后空格 makeArray():类数组转换真数组 inArray():数组版indexOf merge():合并数组 grep():过滤新数组 map():映射新数组 each方法: each是遍历集合用的方法,也是一个加强版的循环操作.例如: var arr = { Name: 'jam', Age: 15 }; $.each(arr, function (key, val) { console.log(key + ":&quo

jQuery 源码分析(十三) 数据操作模块 DOM属性 详解

jQuery的属性操作模块总共有4个部分,本篇说一下第2个部分:DOM属性部分,用于修改DOM元素的属性的(属性和特性是不一样的,一般将property翻译为属性,attribute翻译为特性) DOM属性的静态方法接口如下: prop(elem, name, value)    ;设置或读取DOM属性,有两种用法,如下 ·$.prop(elem,name,value)      ;传入第三个参数表示设置elem元素的name属性值为value ·$.prop(elem,name,)      

jQuery 源码分析(十五) 数据操作模块 val详解

jQuery的属性操作模块总共有4个部分,本篇说一下最后一个部分:val值的操作,也是属性操作里最简单的吧,只有一个API,如下: val(vlaue)        ;获取匹配元素集合中第一个元素的当前值,或者设置匹配元素集合中每个元素的值,有三种用法: val()        ;没有参数,获取第一个匹配元素的当前值 val(value)      ;为每个匹配元素设置value值        ;如果为null则表示设置值为空 val(func)       ;设置每个匹配元素为函数fun

LiteDB源码解析系列(2)数据库页详解

1.LiteDB页的技术工作原理 LiteDB虽然是单个文件类型的数据库,但是数据库有很多信息,例如索引,集合,文件等.为了管理这些信息,LiteDB实现了数据库页的概念.页是一个拥有4096 字节的 存储相同信息的地址块.页也是操作磁盘文件(读写)的最小单元.LiteDB有6中页类型,类图如下: 1.1 BasePage BasePage是数据库页类型的父类,使用一个常量字段PAGE_SIZE定义了页的大小为4096个字节. 主要的属性说明如下: PageID:一个uint类型的ID,在Lit

JDK源码学习(2)-String.intern()方法详解

1.方法intern()为java内部方法,如下  public native String intern(); native方法为通过jvm进行运行,jdk8中隐藏了该方法的具体处理方法. 2.作用:该方法注释为 "如果常量池中存在当前字符串, 就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回". 3.测试代码一 public static void main(String[] args) { String s1 = new String(&

jQuery源码解析(jQuery对象的实例属性和方法)

1.记录版本号 以及 修正constructor指向 jquery: core_version, constructor: jQuery, 因为jQuery.prototype={ ... } 这种写法将自动生成的jQuery.prototype.constructor属性覆盖删除,所以需要重新修正(指向其构造函数 jQuery).2.init() 初始化方法: init()方法最终返回的是this -jQuery(其实是jQuery.prototype.init)方法的实例对象. 实例对象继承