zoukankan      html  css  js  c++  java
  • jQuery的回调管理机制(二)

    jQuery.extend({
      /*
       * deferred对象的一大好处,就是它允许你自由添加多个回调函数。
       * $.ajax("test.html")
           .done(function(){ alert("哈哈,成功了!");} )
           .fail(function(){ alert("出错啦!"); } )
           .done(function(){ alert("第二个回调函数!");} );
       *deferred对象的另一大好处,就是它允许你为多个事件指定一个回调函数,这是传统写法做不到的。
          当两个操作都成功了才执行成功的回调函数,否则执行失败的回调函数
          $.when($.ajax("test1.html"), $.ajax("test2.html"))
           .done(function(){ alert("哈哈,成功了!"); })
           .fail(function(){ alert("出错啦!"); });
       *deferred对象的最大优点,就是它把这一套回调函数接口,从ajax操作扩展到了所有操作。
        也就是说,任何一个操作----不管是ajax操作还是本地操作,也不管是异步操作还是同步操作----
        都可以使用deferred对象的各种方法,指定回调函数。
       *deferred对象有三种执行状态----未完成,已完成和已失败。
       */
      Deferred: function( func ) {
        var tuples = [
        // action, add listener, listener list, final state

          //不同动作、监听、回调、最终状态组织起来的一个数组,将用它生成三组事件监听方法
          [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
          [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
          [ "notify", "progress", jQuery.Callbacks("memory") ]
        ],
        state = "pending",

        // 返回当前的执行状态
        promise = {
          state: function() {
          return state;
          },
          // 不管执行状态是resolve还是reject,都执行回调。
          always: function() {

            // deferred是在该回调函数中定义的一个对象(后面),它将作为返回值被返回,大部分方法将被绑定在该对象中
            deferred.done( arguments ).fail( arguments );
            return this;
          },
          // 参数可传入三个函数,第一个是成功的回调,第二个是失败的回调,第三个。。呃。。

          // 这个方法有些迷惑。。
          then: function( /* fnDone, fnFail, fnProgress */ ) {
            var fns = arguments;
            // 递归调用jQuery.Deferred()方法,并传入func。这些func将被加入回调列表中
            return jQuery.Deferred(function( newDefer ) {
              jQuery.each( tuples, function( i, tuple ) {
                var action = tuple[ 0 ],
                  //判断参数是不是函数,如果是就赋值给fn,第一参数对应done,第二个参数对应fail,。。。
                  fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
                deferred[ tuple[1] ](function() {
                  //这里的this指,调用done、fail的对象,arguments指调用时传入的参数,比如函数。
                  var returned = fn && fn.apply( this, arguments );
                  if ( returned && jQuery.isFunction( returned.promise ) ) {
                    returned.promise()
                      .done( newDefer.resolve )
                      .fail( newDefer.reject )
                      .progress( newDefer.notify );
                  } else {
                    newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
                  }
                });
              });
              fns = null;
            }).promise();
          },
          // 提供一个方法将promise对象扩展到obj对象上。如果没有obj对象,则直接返回promise对象。
          promise: function( obj ) {
            return obj != null ? jQuery.extend( obj, promise ) : promise;
          }
        },

        // 所有封装的方法都会绑定到该对象上返回
        deferred = {};

        //为了向后兼容,以前都是用promise.pipe?
        promise.pipe = promise.then;

        // 遍历之前定义的动作、监听、回调、最终状态组成的数组,进行初始化操作
        jQuery.each( tuples, function( i, tuple ) {
          // 取得数组当中的 jQuery.Callbacks("once memory"),并将执行结果赋值给list。
          var list = tuple[ 2 ],
          //取出数组中的表示最终状态的字符串 “resolved rejected”
          stateString = tuple[ 3 ];

          //将list,也就是jQuery.Callback()方法返回的self对象中的add方法,绑定到promise.resolve/reject/notify上
          promise[ tuple[1] ] = list.add;

          // 如果stateString有值,以为数组中的第三个小数组中是没有最终状态值的,所以需要if做判断
          if ( stateString ) {

            // 调用Callbask返回的对象中的add方法,向回调列表中增加三个回调方法:一个匿名函数(改变最终状态),一个disable,一个lock
            list.add(function() {
              // state = [ resolved | rejected ]
              state = stateString;

              // [ reject_list | resolve_list ].disable; progress_list.lock
            }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
          }

          //将resolve()、reject()、notify()方法绑定到deferred对象上并暴露出来提供给用户调用
          deferred[ tuple[0] ] = function() {
            //调用deferred.resovleWith/rejectWith/notifyWith方法,这些方法是在下面定义的
            deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
            return this;
          };
          //将jQuery.Callback()方法返回的self对象中的fireWith方法绑定到deferred.resovleWith/rejectWith/notifyWith上
          deferred[ tuple[0] + "With" ] = list.fireWith;
        });

        // 将promise对象所有的方法和属性扩展到deferred对象上,使之具有promise所具有的方法和属性,但promise中并不会包含一些不想暴露的方法,所以使用时,可以返回deferred.promise对象
        promise.promise( deferred );

        //如果有传入的func,则在deferred对象执行环境执行func,支持另外一种使用Deferred的方法。例如:$.Deferred( function(){} );
        if ( func ) {
          func.call( deferred, deferred );
        }

        // 返回deferred对象
        return deferred;
      },

      //多个方法全都执行完毕后,执行回调函数
      when: function( subordinate /* , ..., subordinateN */ ) {

        ......

      }
    });

  • 相关阅读:
    Linux使用locate命令定位文件
    【iOS开发-54】案例学习:通过UIScrollView的缩放图片功能练习代理模式的详细实现
    数据结构—单链表(类C语言描写叙述)
    怎样訪问pcie整个4k的配置空间
    [Swift]LeetCode988. 从叶结点开始的最小字符串 | Smallest String Starting From Leaf
    [Swift]LeetCode985. 查询后的偶数和 | Sum of Even Numbers After Queries
    [Swift]LeetCode494. 目标和 | Target Sum
    [Swift]LeetCode493. 翻转对 | Reverse Pairs
    [Swift]LeetCode491. 递增子序列 | Increasing Subsequences
    [Swift]LeetCode488. 祖玛游戏 | Zuma Game
  • 原文地址:https://www.cnblogs.com/charling/p/3456781.html
Copyright © 2011-2022 走看看