Implements joined jQuery.when statements. Makes it so calling jQuery.when with no parameter returns a resolved promise. Ensures promise method on promises supports the promise(obj) signature. Ensures a deferred and its promise always return the same promise (itself for the promise). Unit tests provided.

This commit is contained in:
jaubourg 2011-01-16 17:41:39 +01:00
parent cfca6d3836
commit c272f5f7da
2 changed files with 79 additions and 14 deletions

View File

@ -898,9 +898,10 @@ jQuery.extend({
Deferred: function( func ) { Deferred: function( func ) {
var deferred = jQuery._Deferred(), var deferred = jQuery._Deferred(),
failDeferred = jQuery._Deferred(); failDeferred = jQuery._Deferred(),
promise;
// Add errorDeferred methods and redefine cancel // Add errorDeferred methods, then and promise
jQuery.extend( deferred , { jQuery.extend( deferred , {
then: function( doneCallbacks , failCallbacks ) { then: function( doneCallbacks , failCallbacks ) {
@ -914,13 +915,15 @@ jQuery.extend({
// Get a promise for this deferred // Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object // If obj is provided, the promise aspect is added to the object
promise: function( obj ) { promise: function( obj ) {
obj = obj || {}; if ( obj == null ) {
jQuery.each( "then done fail isResolved isRejected".split( " " ) , function( _ , method ) { if ( promise ) {
return promise;
}
promise = obj = {};
}
jQuery.each( "then done fail isResolved isRejected promise".split( " " ) , function( _ , method ) {
obj[ method ] = deferred[ method ]; obj[ method ] = deferred[ method ];
}); });
obj.promise = function() {
return obj;
};
return obj; return obj;
} }
@ -942,10 +945,32 @@ jQuery.extend({
// Deferred helper // Deferred helper
when: function( object ) { when: function( object ) {
object = object && jQuery.isFunction( object.promise ) ? var args = arguments,
object : length = args.length,
jQuery.Deferred().resolve( object ); deferred = length <= 1 && object && jQuery.isFunction( object.promise ) ?
return object.promise(); object :
jQuery.Deferred(),
promise = deferred.promise(),
resolveArray;
if ( length > 1 ) {
resolveArray = new Array( length );
jQuery.each( args, function( index, element, args ) {
jQuery.when( element ).done( function( value ) {
args = arguments;
resolveArray[ index ] = args.length > 1 ? slice.call( args , 0 ) : value;
if( ! --length ) {
deferred.fire( promise, resolveArray );
}
}).fail( function() {
deferred.fireReject( promise, arguments );
});
return !deferred.isRejected();
});
} else if ( deferred !== object ) {
deferred.resolve( object );
}
return promise;
}, },
// Use of jQuery.browser is frowned upon. // Use of jQuery.browser is frowned upon.

View File

@ -21,7 +21,7 @@ test("jQuery()", function() {
equals( jQuery(null).length, 0, "jQuery(null) === jQuery([])" ); equals( jQuery(null).length, 0, "jQuery(null) === jQuery([])" );
equals( jQuery("").length, 0, "jQuery('') === jQuery([])" ); equals( jQuery("").length, 0, "jQuery('') === jQuery([])" );
var obj = jQuery("div") var obj = jQuery("div");
equals( jQuery(obj).selector, "div", "jQuery(jQueryObj) == jQueryObj" ); equals( jQuery(obj).selector, "div", "jQuery(jQueryObj) == jQueryObj" );
// can actually yield more than one, when iframes are included, the window is an array as well // can actually yield more than one, when iframes are included, the window is an array as well
@ -1003,7 +1003,7 @@ test("jQuery._Deferred()", function() {
test("jQuery.Deferred()", function() { test("jQuery.Deferred()", function() {
expect( 4 ); expect( 6 );
jQuery.Deferred( function( defer ) { jQuery.Deferred( function( defer ) {
strictEqual( this , defer , "Defer passed as this & first argument" ); strictEqual( this , defer , "Defer passed as this & first argument" );
@ -1023,11 +1023,16 @@ test("jQuery.Deferred()", function() {
}, function() { }, function() {
ok( true , "Error on reject" ); ok( true , "Error on reject" );
}); });
var tmp = jQuery.Deferred();
strictEqual( tmp.promise() , tmp.promise() , "Test deferred always return same promise" );
strictEqual( tmp.promise() , tmp.promise().promise() , "Test deferred's promise always return same promise as deferred" );
}); });
test("jQuery.when()", function() { test("jQuery.when()", function() {
expect( 21 ); expect( 23 );
// Some other objects // Some other objects
jQuery.each( { jQuery.each( {
@ -1050,6 +1055,10 @@ test("jQuery.when()", function() {
} ); } );
ok( jQuery.isFunction( jQuery.when().then( function( resolveValue ) {
strictEqual( resolveValue , undefined , "Test the promise was resolved with no parameter" );
} ).promise ) , "Test calling when with no parameter triggers the creation of a new Promise" );
var cache, i; var cache, i;
for( i = 1 ; i < 4 ; i++ ) { for( i = 1 ; i < 4 ; i++ ) {
@ -1064,6 +1073,37 @@ test("jQuery.when()", function() {
} }
}); });
test("jQuery.when() - joined", function() {
expect(8);
jQuery.when( 1, 2, 3 ).done( function( a, b, c ) {
strictEqual( a , 1 , "Test first param is first resolved value - non-observables" );
strictEqual( b , 2 , "Test second param is second resolved value - non-observables" );
strictEqual( c , 3 , "Test third param is third resolved value - non-observables" );
}).fail( function() {
ok( false , "Test the created deferred was resolved - non-observables");
});
var successDeferred = jQuery.Deferred().resolve( 1 , 2 , 3 ),
errorDeferred = jQuery.Deferred().reject( "error" , "errorParam" );
jQuery.when( 1 , successDeferred , 3 ).done( function( a, b, c ) {
strictEqual( a , 1 , "Test first param is first resolved value - resolved observable" );
same( b , [ 1 , 2 , 3 ] , "Test second param is second resolved value - resolved observable" );
strictEqual( c , 3 , "Test third param is third resolved value - resolved observable" );
}).fail( function() {
ok( false , "Test the created deferred was resolved - resolved observable");
});
jQuery.when( 1 , errorDeferred , 3 ).done( function() {
ok( false , "Test the created deferred was rejected - rejected observable");
}).fail( function( error , errorParam ) {
strictEqual( error , "error" , "Test first param is first rejected value - rejected observable" );
strictEqual( errorParam , "errorParam" , "Test second param is second rejected value - rejected observable" );
});
});
test("jQuery.subclass", function(){ test("jQuery.subclass", function(){
expect(378); expect(378);