jQuery deferred学习笔记

 

简介


 

 

  在jQuery1.5.0版本引入,为了实现Deferred对象,jQuery改写了ajax。是由jQuery.Deferred()方法创建的链式对象。

  $.Deferred在jQuery代码自身四处被使用(promiseDOM ready、Ajax、Animation)

  

  特性:使用Deferred对象可以添加多个回调函数; 延迟特性,处理耗时操作问题

  •  register multiple callbacks into callback queues
  •  invoke callback queues
  •  relay the success or failure state of any synchronous or asynchronous function

 

主要源码


 

 

jQuery1.9.1源码如下:

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() {
                   .....
                },
                always: function() {
                   ....
                },
                then: function( /* fnDone, fnFail, fnProgress */ ) {
           ....
                },
                // Get a promise for this deferred
                // If obj is provided, the promise aspect is added to the object
                promise: function( obj ) {
                  .....
                }
            },
            deferred = {};

        // Keep pipe for back-compat
        promise.pipe = promise.then;

        // Add list-specific methods
        jQuery.each( tuples, function( i, tuple ) {
            ...
            deferred[ tuple[0] + "With" ] = list.fireWith;
        });

        // Make the deferred a promise
        promise.promise( deferred );

        // Call given func if any
        if ( func ) {
            func.call( deferred, deferred );
        }

        // All done!
        return deferred;
    },

    // Deferred helper
    when: function( subordinate /* , ..., subordinateN */ ) {
    ....
    return deferred.promise();
  }
    
});

Callbacks 是jQuery的回调对象,用于添加回调、删除回调、执行回调等

jQuery.Callbacks = function( options ) {// Actual Callbacks object
        self = {
            // Add a callback or a collection of callbacks to the list
            add: function() {
                ...
            },
            // Remove a callback from the list
            remove: function() {
               ....
            },
       ....
// Call all the callbacks with the given arguments fire: function() { self.fireWith( this, arguments ); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!fired; } }; return self; };

 

 

methods


 

   jQuery下两个方法:

  

$.Deffered() ——创建Deffered对象,var deferred = $.Deffered();

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

 

  

  Deffered对象包含如下方法:

deferred.always()——执行回调函数,不管deffered 对象是 状态resolved或者是rejected
           (即不管成功或者失败,对应ajax中complete)(关于执行状态看下一章节)

deferred.done()——当Deferred对象状态为resolved时执行回调函数

deferred.fail()——当Deferred对象状态为rejected时执行回调函数

deferred.then()——执行回调函数,deferred 对象是 状态resolved或者是rejected 或者是 in progress

 

deferred.isRejected()——判断状态是否为rejected

deferred.isResolved()——判断状态是否为resolved

deffered.state()——判断当前状态

 

deferred.promise()——返回Deferred的promise对象

deferred.reject()——reject a deferred对象,即将状态转为rejected( with the given args.)

deferred.rejectWith()——与上面reject的区别:with the given context and args. 下面类似

deferred.resolve()——即将状态转为resolve  
              
deferred.resolveWith()—— 

deferred.notify()——call the progressCallbacks  

deferred.notifyWith()——  
 
 

deferred.pipe()——过滤参数
 

一般done/resolve fail/reject progress/notify 对应使用



执行状态


 

 

  Deffered对象三种执行状态: resolved(已完成)、未完成、rejected(失败)

  1. 如果执行状态是resovled,Deffered对象会立刻调用done()方法指定的回调函数

  2. 如果执行状态是rejected,Deffered对象会立刻调用fail()方法指定的回调函数

  3.  如果执行状态是未完成,Deffered对象会继续等待或者是调用progress()方法指定的回调函数

 

ajax及简单链式操作


 

eg:

ajax方式:

$.ajax("test.jsp").success(function(result){alert("success! data is :"+result);})   
                  .error(function(){alert("Error")})
           .complete(function(){alert("complete!")});

或者:

$.ajax({
        url:"test.jsp",
        success:function(result){alert("success! data is :"+result);},
     error: function(){alert("Error!");},
       complete:function(){alert("complete!")},
});

 

 

使用Deferred:

由于$.ajax 方法和$.get方法返回的是jqXHR对象(源自Deferred对象)因而上面的操作可以以下面的方式实现。

    $.ajax("test.jsp").done(function(result){alert("success! data is :"+result);})
                      .fail(function(){alert("Error")})
             .always(function(){alert("finished");});

 

 注意:$.ajax()中jqXHR.success(), jqXHR.error(), jqXHR.complete(), 在jquery 1.8中已经弃用,应该使用done(),fail()和always()

 

done/resolve   fail/reject   progress/notify


 

 

done/resolve

var dfd = $.Deferred();

dfd.done(function(){
    console.log("###############")
});

$("button").on("click",function(){
    dfd.resolve();
}); 

点击按钮,输出  ###############

 

fail/reject

var dfd = $.Deferred();

dfd.fail(function(){
    console.log("###############")
});

$("button").on("click",function(){
    dfd.reject();
}); 

点击按钮,输出  ###############

 

progress/notify

eg1:

var dfd = $.Deferred();

dfd.progress(function(){
    console.log("###############")
});

$("button").on("click",function(){
    dfd.notify();
}); 

点击按钮,输出  ###############

 

eg2:使用notify间隔的执行回调函数

var dfd = $.Deferred();

dfd.progress(function(){
    console.log("###############");
});

$("button").on("click",function(){
    setInterval(function(){
        dfd.notify();
    },1000);
    
});  

点击按钮,每1s输出一次##################

 

 

执行多个回调函数


 

eg1:

    $.ajax("test.jsp").done(function(){console.log("the first callback");})
                      .done(function(){console.log("the second callback");})
                      .done(function(){console.log("the third callback");})
                      .fail(function(){console.log("Error")});

或者:

$.ajax("test.jsp").success(function(){console.log("the first callback");})
           .success(function(){console.log("the second callback");})
           .success(function(){console.log("the third callback");})
           .error(function(){console.log("Error")});

 

输出:

the first callback
the second callback
the third callback

 

 

eg2:

deferred对象的done方法定义如下:deferred.done( doneCallbacks [, doneCallbacks ] ) 可以传入 array of functions

success也可达到相同效果,但是已弃用不建议使用

     $.ajax("test.jsp").done([f1,f2,f3],[f2,f3])
                      .done(function(){console.log("the fourth callback");})
                      .fail(function(){alert("Error")});
    function f1(){
        console.log("the first callback");
    }
    function f2(){
        console.log("the second callback");
    }
    function f3(){
        console.log("the third callback");
    }

输出结果如下:

the first callback
the second callback
the third callback
the second callback
the third callback
the fourth callback

 

 

eg3: 使用jQuery.Deferred()创建Deferred对象

简单使用done方法和resolve方法

function f1(){
    console.log("the first callback");
}
function f2(){
    console.log("the second callback");
}
function f3(){
    console.log("the third callback");
} 

var dfd = $.Deferred();
dfd.done([f1,f2,f3],[f2,f3])
   .done(function(){console.log("finished");});
$("button").on("click",function(){
    dfd.resolve();
});

点击button,输出:

the first callback
the second callback
the third callback
the second callback
the third callback
finished

 

eg4. 给resolve添加args

function f1(arg){
    console.log(arg+"the first callback");
}
function f2(arg){
    console.log(arg+"the second callback");
}
function f3(arg){
    console.log(arg+"the third callback");
} 

var dfd = $.Deferred();
dfd.done([f1,f2,f3],[f2,f3])
   .done(function(){console.log("finished");})
   .always(function(arg){console.log(arg+"end");});
   
$("button").on("click",function(){
    dfd.resolve("###############");
});

输出如下:

###############the first callback
###############the second callback
###############the third callback
###############the second callback
###############the third callback
finished
###############end

 

 then和pipe


 

 pipe

使用pipe可以过滤参数,但是jQuery 1.8后已经启用pipe方法,建议使用then

pipe方法定义为:deferred.pipe( [doneFilter ] [, failFilter ] [, progressFilter ] )    returns a new promise

eg1:一次性定义done fail 和progress

function f1() {
    console.log('done');
}
function f2() {
    console.log('fail');
}
function f3() {
    console.log('progress');
}
var deferred = $.Deferred();
deferred.pipe(f1, f2, f3);
$("button").on("click",function(){
    deferred.reject();
});

点击按钮,输出 fail, 可以根据需要修改deferred.reject 为resolve或者是notify

 

eg2: 

var dfd = $.Deferred();
dfd.pipe(function(arg){return "(*^__^*)"+arg;});

dfd.done(function(arg){
    console.log(arg)
});

$("button").on("click",function(){
    dfd.resolve("###############");
});

点击按钮输出:

(*^__^*)###############

 

eg3:

var dfd = $.Deferred();
    argFilter = dfd.pipe(null, function(arg){return "(*^__^*)"+arg;});

argFilter.fail(function(arg){
    console.log(arg)
});

$("button").on("click",function(){
    dfd.reject("###############");
});

输出结果同上

 

 then 

 deferred.then( [doneFilter ] [, failFilter ] [, progressFilter ] )  

 

function f1() {
    console.log('done');
}
function f2() {
    console.log('fail');
}
function f3() {
    console.log('progress');
}
var deferred = $.Deferred();
deferred.then(f1, f2, f3);
$("button").on("click",function(){
    deferred.reject();
});

效果同pipe

 

 when为多个操作指定回调函数


 

jQuery.when(deferreds);

如果传入单个deferred, 返回promise对象,后面可以链式添加then等方法

如果传入多个deferred,返回a new master deferred对象,该对象集合所有deferred对象的状态,如果所有deferred对象是resollve则结果是resolve,如果有一个是reject则结果是reject

 

eg1:

$.when($.ajax("test.jsp")).done(function(){console.log("done");});

结果:

GET http://localhost:8080/javascript/jQuery/test.jsp  200 OK 83ms    

done

 

eg2:

function f1() {
    console.log('done');
}
function f2() {
    console.log('fail');
}
function f3() {
    console.log('progress');
}
$.when($.ajax("test.jsp")).then(f1,f2,f3);

结果同上

 

eg3:

$.when($.ajax("test.jsp"),$.ajax("demo.jsp")).done(function(){console.log("done");});

结果:

GET http://localhost:8080/javascript/jQuery/test.jsp  200 OK 83ms    

GET http://localhost:8080/javascript/jQuery/demo.jsp   200 OK 460ms    

done

 

eg4:

 

 <style>
div {
    height: 50px;
    width: 50px;
    float: left;
    margin-right: 10px;
    display: none;
    background-color: #090;
  }
  </style>
<button>button</button>
<div></div>
<div></div>
<div></div>
<div></div>

 

var effect = function() {
  return $( "div" ).fadeIn( 800 ).delay( 1200 ).fadeOut();
};
 
$( "button" ).on( "click", function() {
  $.when( effect() ).done(function() {
    console.log("finished");
  });
});

effect()方法执行完后输出 finished;

 

 .promise()


 

 

.promise([type][,target])  return a promise object   当所有与其相关的action结束后变为resolve状态

(The .promise() method returns a dynamically generated Promise that is resolved once all actions of a certain type bound to the collection, queued or not, have ended.)

 

eg1:

var button = $( "<button>" );     
button.promise().done(function( arg ) {
     console.log( this === button && arg === button );  //true
});

 

eg2:

 <style>
div {
    height: 50px;
    width: 50px;
    float: left;
    margin-right: 10px;
    display: none;
    background-color: #090;
  }
  </style>
<button>button</button>
<div></div>
<div></div>
<div></div>
<div></div>

 

$( "button" ).on( "click", function() {
 
  $( "div" ).each(function( i ) {
    $( this ).fadeIn().fadeOut( 1000 * ( i + 1 ) );
  });
 
  $( "div" ).promise().done(function() {
    console.log("finished");
  });
});

 

animation结束后输出finished,效果等价于when 中的eg4

 

 

相关: http://api.jquery.com/category/deferred-object/

     http://www.cnblogs.com/littledu/articles/2811728.html

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

 

posted @ 2014-05-23 18:45  wishyouhappy  阅读(1117)  评论(0编辑  收藏  举报