`
xing_kenny
  • 浏览: 3364 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

deferred.then() 和 deferred.done().fail() 的不同

阅读更多
function log(s) { $('body').append(s + '<br/>'); }

var value1, value2, value3,
defer = jQuery.Deferred();
defer
.done(function(){
    // console.log("I am 1st done");
})
    .done(function(a,b){
        value1 = a;
        value2 = b;
    })
    .done(function(a,b){
        log("a = " + a);
        log("b = " + b);
        return a * b;
    })
    .done(function( result ) {
        log("result = " + result);
        value3 = result;
    })
    .then(function( a, b ) {
        log("a = " + a);
        log("b = " + b);
        return a * b;
    })
    .done(function( result ) {
        log("result = " + result);
        value3 = result;
    })
    .then(function( a, b ) {
        log("a = " + a);
        log("b = " + b);
        return a * b;
    })
    .done(function( result ) {
        log("result = " + result);
        value3 = result;
    })
    ;
defer.resolve( 2, 3 );​

上面這段代碼的輸出是:

a = 2
b = 3
result = 2
a = 2
b = 3
result = 6
a = 6
b = undefined
result = NaN

參見:http://jsfiddle.net/JqRc9/

then()和done().fail().process()的差別是
then: function( /* fnDone, fnFail, fnProgress */ )會生成一個新的deferred,return jQuery.Deferred(function( newDefer )。初始化這個新deferred時,執行function( newDefer ),這個function添加一個callback func到前一個deferred。這個callback func是從老deferred到新deferred的橋樑,從deferred[ tuple[1]]到newDefer[ tuple[0] + "With" ]。對於每個deferred[ tuple[1] ],如果有對應的then()所帶function( /* fnDone, fnFail, fnProgress 之一*/ ),這個函數就是
function () {
    var returned = 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, [ returned ] );
    }
}
        then所帶函數會被執行,返回returned,如果jQuery.isFunction( returned.promise ),则调用这个returned.promise的done、fail和progress,它们会对应触发newDefer的resolve、reject、notify; 否则 returned 傳入新的deferred,newDefer执行action + “with”;
        如果沒有對應的then()所帶函數,簡單執行newDefer[ action ]。

    上面的第一個result是第一個result的最后一個done()的輸出,前一個done的return不會傳遞到這裡,所以result是resolve的第一個參數。
第二個result是第二個deferred的輸出,第一個then所帶的function的輸入,傳入第二個deferred,因此第五個done能夠接受到2*3的result。
第三個result是第三個deferred的輸出,第二個then執行時,只有a,沒有b,所以result是NaN。

更多的log如下:

start deferred.js:100
************************************************ deferred.js:101
deferred.key = 29814 -> tuple[1] = done jquery.js:1195
callback.key = 81354 jquery.js:1196
In callback[81354] ---- list.length to 1 jquery.js:1030
list.push =  jquery.js:1031
function () {
// state = [ resolved | rejected ]
state = stateString;

// [ reject_list | resolve_list ].disable; progress_list.lock
} jquery.js:1032
In callback[81354] ---- list.length to 2 jquery.js:1030
list.push =  jquery.js:1031
function () {
list = stack = memory = undefined;
return this;
} jquery.js:1032
In callback[81354] ---- list.length to 3 jquery.js:1030
list.push =  jquery.js:1031
function () {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
} jquery.js:1032
deferred.key = 29814 -> tuple[1] = fail jquery.js:1195
callback.key = 4458 jquery.js:1196
In callback[4458] ---- list.length to 1 jquery.js:1030
list.push =  jquery.js:1031
function () {
// state = [ resolved | rejected ]
state = stateString;

// [ reject_list | resolve_list ].disable; progress_list.lock
} jquery.js:1032
In callback[4458] ---- list.length to 2 jquery.js:1030
list.push =  jquery.js:1031
function () {
list = stack = memory = undefined;
return this;
} jquery.js:1032
In callback[4458] ---- list.length to 3 jquery.js:1030
list.push =  jquery.js:1031
function () {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
} jquery.js:1032
deferred.key = 29814 -> tuple[1] = progress jquery.js:1195
callback.key = 67133 jquery.js:1196
In callback[81354] ---- list.length to 4 jquery.js:1030
list.push =  jquery.js:1031
function (){
// console.log("I am 1st done");
} jquery.js:1032
In callback[81354] ---- list.length to 5 jquery.js:1030
list.push =  jquery.js:1031
function (a,b){
value1 = a;
value2 = b;
} jquery.js:1032
In callback[81354] ---- list.length to 6 jquery.js:1030
list.push =  jquery.js:1031
function (a,b){
console.log("a = " + a);
console.log("b = " + b);
return a * b;
} jquery.js:1032
In callback[81354] ---- list.length to 7 jquery.js:1030
list.push =  jquery.js:1031
function ( result ) {
console.log("result = " + result);
value3 = result;
} jquery.js:1032
deferred.key = 55257 -> tuple[1] = done jquery.js:1195
callback.key = 24912 jquery.js:1196
In callback[24912] ---- list.length to 1 jquery.js:1030
list.push =  jquery.js:1031
function () {
// state = [ resolved | rejected ]
state = stateString;

// [ reject_list | resolve_list ].disable; progress_list.lock
} jquery.js:1032
In callback[24912] ---- list.length to 2 jquery.js:1030
list.push =  jquery.js:1031
function () {
list = stack = memory = undefined;
return this;
} jquery.js:1032
In callback[24912] ---- list.length to 3 jquery.js:1030
list.push =  jquery.js:1031
function () {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
} jquery.js:1032
deferred.key = 55257 -> tuple[1] = fail jquery.js:1195
callback.key = 39457 jquery.js:1196
In callback[39457] ---- list.length to 1 jquery.js:1030
list.push =  jquery.js:1031
function () {
// state = [ resolved | rejected ]
state = stateString;

// [ reject_list | resolve_list ].disable; progress_list.lock
} jquery.js:1032
In callback[39457] ---- list.length to 2 jquery.js:1030
list.push =  jquery.js:1031
function () {
list = stack = memory = undefined;
return this;
} jquery.js:1032
In callback[39457] ---- list.length to 3 jquery.js:1030
list.push =  jquery.js:1031
function () {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
} jquery.js:1032
deferred.key = 55257 -> tuple[1] = progress jquery.js:1195
callback.key = 78608 jquery.js:1196
In callback[81354] ---- list.length to 8 jquery.js:1030
list.push =  jquery.js:1031
function () {
var returned = 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 === deferred ? newDefer : this, [ returned ] );
newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, [ returned ] ); }
} jquery.js:1032
In callback[4458] ---- list.length to 4 jquery.js:1030
list.push =  jquery.js:1031
function () {
deferred[ tuple[0] + "With" ]( promise, arguments );
return this;
} jquery.js:1032
In callback[67133] ---- list.length to 1 jquery.js:1030
list.push =  jquery.js:1031
function () {
deferred[ tuple[0] + "With" ]( promise, arguments );
return this;
} jquery.js:1032
In callback[24912] ---- list.length to 4 jquery.js:1030
list.push =  jquery.js:1031
function ( result ) {
console.log("result = " + result);
value3 = result;
} jquery.js:1032
deferred.key = 83451 -> tuple[1] = done jquery.js:1195
callback.key = 13998 jquery.js:1196
In callback[13998] ---- list.length to 1 jquery.js:1030
list.push =  jquery.js:1031
function () {
// state = [ resolved | rejected ]
state = stateString;

// [ reject_list | resolve_list ].disable; progress_list.lock
} jquery.js:1032
In callback[13998] ---- list.length to 2 jquery.js:1030
list.push =  jquery.js:1031
function () {
list = stack = memory = undefined;
return this;
} jquery.js:1032
In callback[13998] ---- list.length to 3 jquery.js:1030
list.push =  jquery.js:1031
function () {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
} jquery.js:1032
deferred.key = 83451 -> tuple[1] = fail jquery.js:1195
callback.key = 94472 jquery.js:1196
In callback[94472] ---- list.length to 1 jquery.js:1030
list.push =  jquery.js:1031
function () {
// state = [ resolved | rejected ]
state = stateString;

// [ reject_list | resolve_list ].disable; progress_list.lock
} jquery.js:1032
In callback[94472] ---- list.length to 2 jquery.js:1030
list.push =  jquery.js:1031
function () {
list = stack = memory = undefined;
return this;
} jquery.js:1032
In callback[94472] ---- list.length to 3 jquery.js:1030
list.push =  jquery.js:1031
function () {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
} jquery.js:1032
deferred.key = 83451 -> tuple[1] = progress jquery.js:1195
callback.key = 27374 jquery.js:1196
In callback[24912] ---- list.length to 5 jquery.js:1030
list.push =  jquery.js:1031
function () {
var returned = 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 === deferred ? newDefer : this, [ returned ] );
newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, [ returned ] ); }
} jquery.js:1032
In callback[39457] ---- list.length to 4 jquery.js:1030
list.push =  jquery.js:1031
function () {
deferred[ tuple[0] + "With" ]( promise, arguments );
return this;
} jquery.js:1032
In callback[78608] ---- list.length to 1 jquery.js:1030
list.push =  jquery.js:1031
function () {
deferred[ tuple[0] + "With" ]( promise, arguments );
return this;
} jquery.js:1032
In callback[13998] ---- list.length to 4 jquery.js:1030
list.push =  jquery.js:1031
function ( result ) {
console.log("result = " + result);
value3 = result;
} jquery.js:1032
In callback[81354].fire ---- list.length = 8 jquery.js:995
data = [object Object],[object Arguments] jquery.js:996
list[0] = function () {
// state = [ resolved | rejected ]
state = stateString;

// [ reject_list | resolve_list ].disable; progress_list.lock
} jquery.js:998
list[1] = function () {
list = stack = memory = undefined;
return this;
} jquery.js:998
list[2] = function () {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
} jquery.js:998
list[3] = function (){
// console.log("I am 1st done");
} jquery.js:998
list[4] = function (a,b){
value1 = a;
value2 = b;
} jquery.js:998
list[5] = function (a,b){
console.log("a = " + a);
console.log("b = " + b);
return a * b;
} jquery.js:998
a = 2 deferred.js:113
b = 3 deferred.js:114
list[6] = function ( result ) {
console.log("result = " + result);
value3 = result;
} jquery.js:998
result = 2 deferred.js:118
list[7] = function () {
var returned = 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 === deferred ? newDefer : this, [ returned ] );
newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, [ returned ] ); }
} jquery.js:998
a = 2 deferred.js:122
b = 3 deferred.js:123
In callback[24912].fire ---- list.length = 5 jquery.js:995
data = [object Object],6 jquery.js:996
list[0] = function () {
// state = [ resolved | rejected ]
state = stateString;

// [ reject_list | resolve_list ].disable; progress_list.lock
} jquery.js:998
list[1] = function () {
list = stack = memory = undefined;
return this;
} jquery.js:998
list[2] = function () {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
} jquery.js:998
list[3] = function ( result ) {
console.log("result = " + result);
value3 = result;
} jquery.js:998
result = 6 deferred.js:127
list[4] = function () {
var returned = 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 === deferred ? newDefer : this, [ returned ] );
newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, [ returned ] ); }
} jquery.js:998
a = 6 deferred.js:131
b = undefined deferred.js:132
In callback[13998].fire ---- list.length = 4 jquery.js:995
data = [object Object],NaN jquery.js:996
list[0] = function () {
// state = [ resolved | rejected ]
state = stateString;

// [ reject_list | resolve_list ].disable; progress_list.lock
} jquery.js:998
list[1] = function () {
list = stack = memory = undefined;
return this;
} jquery.js:998
list[2] = function () {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
} jquery.js:998
list[3] = function ( result ) {
console.log("result = " + result);
value3 = result;
} jquery.js:998
result = NaN
end &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

下面这个testcase比较。。。

test( "jQuery.Deferred.then - deferred (done)", function() {

expect( 3 );

var value1, value2, value3,
defer = jQuery.Deferred(),
piped = defer.then(function( a, b ) {
return jQuery.Deferred(function( newDefer ) {
newDefer.reject( a * b );
});
});

piped.fail(function( result ) {
value3 = result;
});
piped.done(function( result ) { //not be executed
console.log("I am piped.done....................................................");
});

defer.done(function( a, b ) {
value1 = a;
value2 = b;
});

defer.resolve( 2, 3 );

strictEqual( value1, 2, "first resolve value ok" );
strictEqual( value2, 3, "second resolve value ok" );
strictEqual( value3, 6, "result of filter ok" );
});

    defer.done.list:
    [3] :從defer到piped
    [4] :done(function( a, b )
    piped.fail.list:
    [3] : function( result ) {
value3 = result;
}
    jQuery.Deferred.fail.list
    [0] :returned.promise()
          .done( newDefer.resolve )
          .fail( newDefer.reject )
  .progress( newDefer.notify );
   
    執行順序:
    1) defer.resolve( 2, 3 );
    2) 執行到defer.done.list[3]時,then所帶function( a, b )觸發,
        生成一個jQuery.Deferred,
        這個jQuery.Deferred構造中,執行
        function( newDefer ) { newDefer.reject( a * b );}
        執行完jQuery.Deferred.fail.list
    3)  jQuery.Deferred 繼續執行
        returned.promise()
          .done( newDefer.resolve )
          .fail( newDefer.reject )
  .progress( newDefer.notify );
        jQuery.Deferred.fail.list[0] 將fire
    4) newDefer.reject 觸發piped.fail.list的執行
    5) 最后執行defer.done.list[4]
    參數傳遞過程,非常隱秘!
    newDefer.reject( a * b );
    jQuery.Deferred.fail.list執行時,
    deferred[ tuple[0] + "With" ] = list.fireWith;
    fireWith: function( context, args ) {
    ...
    fire( args );
    ...
    fire = function( data ) {
         memory = options.memory && data;
    result存到memory裡面,
    然後通過
        list[ firingIndex ].apply( data[ 0 ], data[ 1 ] )
deferred[ tuple[0] + "With" ]( promise, arguments );
    傳出來。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics