zoukankan      html  css  js  c++  java
  • 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。

    加油!

  • 相关阅读:
    开源软件
    delphi 语法 点滴总结clientdataset
    combobox 下拉框 高度 调节 呵呵
    Delphi7中ClientDataSet的排序
    clientdataset 修改记录 成功
    http://bbs.csdn.net/topics/340046630 dbgrid怎么获取当前记录值
    Delphi中StrToDateTime函数TFormatSettings参数的使用
    IncSecond:将一个TDateTime变量加减一定数量的秒数
    clientdataset 做为 单机数据库的 使用 学习
    cmake命令用法整理list命令
  • 原文地址:https://www.cnblogs.com/chaojidan/p/4168139.html
Copyright © 2011-2022 走看看