zoukankan      html  css  js  c++  java
  • jQuery的异步回调对象Deffered分析

      先来思考一个问题:一个需要耗时很长的操作比如setTimeout, ajax请求等,我们需要在延时操作后执行一个函数done。

      比如:

     var wait = function(){
        var tasks = function(){
          alert("执行完毕!");
        };
        setTimeout(tasks,5000);
      };

    在wait执行完毕后,再执行done或者fail函数。

    怎么做?当然,你可以在tasks函数中执行done() 或者 fail() ,但是不够优雅的实现。如果加入异步队列,添加类似jQuery的方法:$.when(wait()).done(function(){}).fail(function(){})。

    怎么做到呢?原理很简单,如代码:

    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("出错啦!"); });

    添加一个变量dfd对象,执行完后,改变dfd的状态,状态改变,同时触发相应的方法。

    具体来看看jQuery源码。

    jQuery为我们抽象了3中状态:done, fail,progress;改变状态的方法:resolve,reject,notify;对应的状态码:resolved,reject;对应的回调的对象:jQuery.Callbacks("once memory")

    来看其映射:

    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") ]
                ]

    deferred对象要依赖于Callbacks对象实现。其解析移步Callbacks篇。

    然后为deffered对象添加相应方法。

    deferred = {};
    // 添加[ resolve | reject | notify ]
    deferred[ tuple[0] ] = function() {
        deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
        return this;
    };
    // 添加[ resolveWith | rejectWith | notifyWith ]
    deferred[ tuple[0] + "With" ] = list.fireWith;
    
    // 返回这个对象
    return deferred;
    
    //继承promise对象
    promise: function( obj ) {
        return obj != null ? jQuery.extend( obj, promise ) : promise;
    }
    
    promise.promise( deferred );

    为promise对象添加相应方法:

    // 添加state, always, then, promise
    promise = {
        state: function() {
            return state;
        },
        always: function() {
            deferred.done( arguments ).fail( arguments );
            return this;
        },
        then: function( /* fnDone, fnFail, fnProgress */ ) {
            var fns = arguments;
            return jQuery.Deferred(function( newDefer ) {
                jQuery.each( tuples, function( i, tuple ) {
                    var action = tuple[ 0 ],
                        fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
                    deferred[ tuple[1] ](function() {
                        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: function( obj ) {
            return obj != null ? jQuery.extend( obj, promise ) : promise;
        }
    },
    // 添加pipe
    promise.pipe = promise.then;
    
    // 添加[ done | fail | progress ] = list.add
    promise[ tuple[1] ] = list.add;

    综上:

    deferred的方法:

    deferred.resolve() 手动改变deferred对象的运行状态为"已完成",从而立即触发done()方法。

    deferred.reject() 这个方法与deferred.resolve()正好相反,调用后将deferred对象的运行状态变为"已失败",从而立即触发fail()方法。

    deferred.notify()  手动改变deferred对象的运行状态为"正在进行"

    deferred.state() 返回状态 

    deferred.always()

    deferred.then() 有时为了省事,可以把done()和fail()合在一起写,这就是then()方法。

    deferred.promise() 没有参数时,返回一个新的deferred对象,该对象的运行状态无法被改变;接受参数时,作用为在参数对象上部署deferred接口。

    deferred.done() 指定操作成功时的回调函数

    deferred.fail() 指定操作失败时的回调函数

    deferred.progress() 指定操作正在进行时的回调函数

    deferred.pipe()

     $.when() 为多个操作指定回调函数。

    promise的方法:

    除了以上改变状态的三个方法(resolve, reject, notify)

    done, fail, progress方法就是回调对象的add方法;

    promise[ tuple[1] ] = list.add;

    resolve, reject, notify方法就是回调对象的fire方法;

    deferred[ tuple[0] ] = function() {
      deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
      return this;
    };

    deferred[ tuple[0] + "With" ] = list.fireWith;

    其中then方法感觉比较复杂,其实是加了pipe方法的内容, 原来内容非常简单

    pipe目前用的不多,意义不大,不详细研究

    最后是when方法,其实是维护一个变量remaining,当其所有都完成时候触发回调。

      

      

  • 相关阅读:
    vue-fullcalendar插件
    iframe 父框架调用子框架的函数
    关于调试的一点感想
    hdfs 删除和新增节点
    hadoop yarn 实战错误汇总
    Ganglia 安装 No package 'ck' found
    storm on yarn(CDH5) 部署笔记
    spark on yarn 安装笔记
    storm on yarn安装时 提交到yarn失败 failed
    yarn storm spark
  • 原文地址:https://www.cnblogs.com/pfzeng/p/4478571.html
Copyright © 2011-2022 走看看