zoukankan      html  css  js  c++  java
  • Deferred

    最近在看deferred,有一些疑问,于是研究了一下,现在理解程度也就是70%-80%

    这个方法基于callbacks,所以说,如果要看原理,最好先看一下callbacks的源码。下面我贴上源码,进行分析一下,会加上自己的理解,我主要困惑在when和then方法上,会重点说一下,这里说一下基本的源码分析网上有很多,大家可以搜一下,这里链接一个when和then方法的例子地址:

    http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html

    http://www.css88.com/jqapi-1.9/deferred.then/

    ok,进入源码jQuery.extend({

    
        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; },
              //无论成功与否都调用里面的参数(一般参数都是函数) always:
    function() { deferred.done( arguments ).fail( arguments ); return this; },
              //分别对应完成后运行的函数,失败后运行的函数,正在运行过程中运行的函数 then:
    function( /* fnDone, fnFail, fnProgress */ ) {
                //保存参数
    var fns = arguments;
                //直接返回一个deferred的方法,即直接返回一个deferred对象,
                //这里的newDefer就是我们的return jQuery.Deferred(。。)的返回的新的deferred对象,源码Deferred方法的参数如果是函数的话
                //会立即执行,源码如下:
    if ( func ) {func.call( deferred, deferred );},此时会把deferred作为参数传递进去
      
                return jQuery.Deferred(function( newDefer ) {              //循环遍历tuples,分别对不同状态注册函数                jQuery.each( tuples, function( i, tuple )                 //取出“动作”:resolve(解决)、reject(拒绝)、notify(通知)
    var action = tuple[ 0 ],
                    //取出对应回调函数,这里的i用的比较巧妙,如果fns[i]不存在返回false,否则返回函数 fn
    = jQuery.isFunction( fns[ i ] ) && fns[ i ]; // deferred[ done | fail | progress ] for forwarding actions to newDefer
                    //这里dererred的各个状态的add方法添加了newDefer的fire方法,以后deferred调用fire的话,这个新的newDefer也同样fire
    deferred[ tuple[1] ](function() {
                       //这里注意一下,这里相当于if(fn){returned = fn.apply(this,arguments)};
                       //这时候的returned相当于函数fn执行完毕之后的结果,后面举例子,就会看到效果了,这个this和arguments就是在fire的时候传递进来的,源码如下(for each中体现的):
                      //deferred[ tuple[0] ] = function() {deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );return this;};
    var returned = fn && fn.apply( this, arguments );
                      //如果返回的结果是一个deferred对象,则把newDefer跟这个deferred对象关联,保证一个fire引起另外一个fire
    if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise() .done( newDefer.resolve ) .fail( newDefer.reject ) .progress( newDefer.notify ); } else {
                         //直接调用各个状态的fireWith方法,如果fn存在就直接把returned放入 newDefer[ action
    + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); } }); }); fns = null; }).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object
             //如果有参数就通过promise扩展obj,即把promise的属性都复制到到obj中,如果obj不存在则直接返回promise
             //promise跟deferred区别在于deferred有很多可以改变对象的方法(rejectWith、resolveWith等),promise没有 promise: function( obj ) { return obj != null ? jQuery.extend( obj, promise ) : promise; } }, deferred = {}; // Keep pipe for back-compat promise.pipe = promise.then; // Add list-specific methods
        //这里主要就是把tuples的各个属性进行一一解析赋值到defferred中,
    jQuery.each( tuples, function( i, tuple ) {
           //list就是各个状态的callbacks的list,stateString是状态
    var list = tuple[ 2 ], stateString = tuple[ 3 ]; // promise[ done | fail | progress ] = list.add
    //把各个状态的done、fail、progress方法直接挂到callbacks的add上面
    promise[ tuple[1] ] = list.add; // Handle state
       //如果状态存在,也就是tuples的前两组
    if ( stateString ) {
              //done和fail状态,分别添加三个函数(改变自己的state,把另外一个状态设置为不可用,把第三个状态锁死),这样为了保证只有一个状态执行例如:done的时候fail和process就不能执行了 list.add(
    function() { // state = [ resolved | rejected ] state = stateString; // [ reject_list | resolve_list ].disable; progress_list.lock
              //这个学一下,i^1,这个是异或运算符,效率高,特点:只有一个是1的时候才等于1
    }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); } // deferred[ resolve | reject | notify ]
    //定义fireWith方法,所谓的修改方法
    deferred[ tuple[0] ] = function() { deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); return this; };
           //把fireWith跟callbacks的fireWith进行绑定 deferred[ tuple[
    0] + "With" ] = list.fireWith; }); // Make the deferred a promise
    //扩展deferred,把promise的属性扩展到defrred中
    promise.promise( deferred ); // Call given func if any
    //刚才上面提到的,Deferred()的参数如果是函数,则立即调用,参数就是将要返回的deferred对象
    if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; }, // Deferred helper
    //这个方法是jq的扩展,他的作用就是把放入其中的N个异步方法做一个计数,知道最后一个方法完成之后,才执行when后面的方法
    when: function( subordinate /* , ..., subordinateN */ ) {
         //定义变量,resolveValues把参数转化成数组
    var i = 0, resolveValues = core_slice.call( arguments ), length = resolveValues.length, // the count of uncompleted subordinates
    //remaining存放参数长度,也就是通过它来通知when是否所有的异步方法都执行完了
    remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
         //如果remaining等于1,则肯定是deferred,如果参数大于1,则新定义一个deferred
    deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values
           //更新remaining长度,以及判断是否是最后一个异步,如果是最后一个,则调用deferred的fire方法,从而触发when()后面的方法调用
    updateFunc = function( i, contexts, values ) { return function( value ) { contexts[ i ] = this; values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; if( values === progressValues ) { deferred.notifyWith( contexts, values ); } else if ( !( --remaining ) ) {
                  //计数为0的时候,调用deferred的fire方法 deferred.resolveWith( contexts, values ); } }; }, progressValues, progressContexts, resolveContexts;
    // add listeners to Deferred subordinates; treat others as resolved if ( length > 1 ) { progressValues = new Array( length ); progressContexts = new Array( length ); resolveContexts = new Array( length ); for ( ; i < length; i++ ) {
              //判断传进来的参数是否是deferred,不是则直接计数减一,是的话,调用deferred的promise()方法返回promise对象,然后添加updateFunc函数,
              //当参数中的函数fire的时候,就调用updateFunc函数,计数减一,直到为0
              //整体思路,就是定义一个全局变量保存总共的参数个数,然后写一个公共函数,分配到各个参数函数中,每次函数执行完毕,就执行公共函数去操作公共变量减一,
    if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { resolveValues[ i ].promise() .done( updateFunc( i, resolveContexts, resolveValues ) ) .fail( deferred.reject ) .progress( updateFunc( i, progressContexts, progressValues ) ); } else { --remaining; } } } // if we're not waiting on anything, resolve the master if ( !remaining ) { deferred.resolveWith( resolveContexts, resolveValues ); } return deferred.promise(); } });

     when函数例子:

    var dtd = $.Deferred(); // 新建一个deferred对象
      var wait = function(dtd){
        var tasks = function(){
          alert("执行完毕!");
          dtd.resolve(); // 改变deferred对象的执行状态
        };
        setTimeout(tasks,5000);
        return dtd;
      };
    $.when(wait(dtd))
      .done(function(){ alert("哈哈,成功了!"); })
      .fail(function(){ alert("出错啦!"); });

    then函数例子:

    var filterResolve = function() {
      var defer = $.Deferred(),
      filtered = defer.then(function( value ) {
        return value * 2;
      });

      defer.resolve( 5 );
      filtered.done(function( value ) {
        alert(value);//10
      });
    };

    filterResolve();

    说说这个then的执行逻辑,在源代码中也提到过

     1)定义一个deferred对象defer

     2)defer的then方法执行过程,可以这么理解

      a)var filtered = $.Deferred(),fn = function(value){return value*2;}

      b)defer.add(filtered.resolve(fn()));

    当调用defer的add的时候,相当于filtered的fire方法,而fire的参数是fn()函数的返回值,

    当filtered再次done(add方法)的时候,直接执行上次的fire方法,而参数也是上一个的参数,参见callbacks的 once memory特性

      

  • 相关阅读:
    1. centos7 的安装
    编写java 程序与Linux进行远程连接并运行linux下的脚本
    java 利用辗除法求两个整数的最大公约数和最小公倍数
    java 给不同成绩分等级
    java 分解质因数
    java中导入 导出
    Mysql 常用命令
    mysql 创建联合主键
    mysql注释
    mysql管理工具navicat的快捷键
  • 原文地址:https://www.cnblogs.com/aishangyizhihu/p/4232142.html
Copyright © 2011-2022 走看看