]> source.dussan.org Git - jquery.git/commitdiff
Deferred: syncronize single and multiple target handling in $.when 2707/head
authorTimmy Willison <timmywillisn@gmail.com>
Wed, 11 Nov 2015 15:35:37 +0000 (10:35 -0500)
committerTimmy Willison <timmywillisn@gmail.com>
Fri, 13 Nov 2015 16:16:26 +0000 (11:16 -0500)
Fixes gh-2546
Fixes gh-2018
Close gh-2707

src/deferred.js
test/unit/deferred.js

index e1af425d483bed28250d93b90a765515444c6464..846528e79581a558c5edb5276b9d7f0cd51c9ec5 100644 (file)
@@ -294,19 +294,17 @@ jQuery.extend( {
        },
 
        // Deferred helper
-       when: function( subordinate /* , ..., subordinateN */ ) {
+       when: function() {
                var method,
                        i = 0,
                        resolveValues = slice.call( arguments ),
                        length = resolveValues.length,
 
                        // the count of uncompleted subordinates
-                       remaining = length !== 1 ||
-                               ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+                       remaining = length,
 
                        // the master Deferred.
-                       // If resolveValues consist of only a single Deferred, just use that.
-                       master = remaining === 1 ? subordinate : jQuery.Deferred(),
+                       master = jQuery.Deferred(),
 
                        // Update function for both resolve and progress values
                        updateFunc = function( i, contexts, values ) {
@@ -316,14 +314,17 @@ jQuery.extend( {
                                        if ( values === progressValues ) {
                                                master.notifyWith( contexts, values );
                                        } else if ( !( --remaining ) ) {
-                                               master.resolveWith( contexts, values );
+                                               master.resolveWith(
+                                                       contexts.length === 1 ? contexts[ 0 ] : contexts,
+                                                       values
+                                               );
                                        }
                                };
                        },
                        progressValues, progressContexts, resolveContexts;
 
                // Add listeners to Deferred subordinates; treat others as resolved
-               if ( length > 1 ) {
+               if ( length > 0 ) {
                        progressValues = new Array( length );
                        progressContexts = new Array( length );
                        resolveContexts = new Array( length );
@@ -345,14 +346,13 @@ jQuery.extend( {
                                                updateFunc( i, progressContexts, progressValues )
                                        );
                                } else {
-                                       --remaining;
+                                       updateFunc( i, resolveContexts, resolveValues )( resolveValues[ i ] );
                                }
                        }
-               }
 
                // If we're not waiting on anything, resolve the master
-               if ( !remaining ) {
-                       master.resolveWith( resolveContexts, resolveValues );
+               } else {
+                       master.resolveWith();
                }
 
                return master.promise();
index 2277df1903188a458b780d351e1b3369e42deac0..1a721d1ee003c0b7ed2f2a465664d5f05d2e1ac9 100644 (file)
@@ -667,7 +667,6 @@ QUnit.test( "jQuery.when", function( assert ) {
                "undefined": undefined,
                "a plain object": {},
                "an array": [ 1, 2, 3 ]
-
        }, function( message, value ) {
                assert.ok(
                        jQuery.isFunction(
@@ -698,12 +697,10 @@ QUnit.test( "jQuery.when", function( assert ) {
        } );
 
        jQuery.each( [ 1, 2, 3 ], function( k, i ) {
-
                jQuery.when( cache || jQuery.Deferred( function() {
                                this.resolve( i );
                        } )
                ).done( function( value ) {
-
                        assert.strictEqual( value, 1, "Function executed" + ( i > 1 ? " only once" : "" ) );
                        cache = value;
                } );
@@ -759,10 +756,8 @@ QUnit.test( "jQuery.when - joined", function( assert ) {
                                expected = shouldResolve ? [ 1, 1 ] : [ 0, undefined ],
                                expectedNotify = shouldNotify && [ willNotify[ id1 ], willNotify[ id2 ] ],
                                code = "jQuery.when( " + id1 + ", " + id2 + " )",
-                               context1 = defer1 && jQuery.isFunction( defer1.promise ) ? defer1.promise() :
-                                       ( defer1.then ? window : undefined ),
-                               context2 = defer2 && jQuery.isFunction( defer2.promise ) ? defer2.promise() :
-                                       ( defer2.then ? window : undefined );
+                               context1 = defer1 && jQuery.isFunction( defer1.promise ) ? defer1.promise() : window,
+                               context2 = defer2 && jQuery.isFunction( defer2.promise ) ? defer2.promise() : window;
 
                        jQuery.when( defer1, defer2 ).done( function( a, b ) {
                                if ( shouldResolve ) {
@@ -880,3 +875,36 @@ QUnit.test( "jQuery.when - chaining", function( assert ) {
 
        defer.resolve( "other deferred" );
 } );
+
+QUnit.test( "jQuery.when - solitary thenables", function( assert ) {
+
+       assert.expect( 1 );
+
+       var done = assert.async(),
+               rejected = new Promise( function( resolve, reject ) {
+                       setTimeout( function() {
+                               reject( "rejected" );
+                       }, 100 );
+               } );
+
+       jQuery.when( rejected ).then(
+               function() {
+                       assert.ok( false, "Rejected, solitary, non-Deferred thenable should not resolve" );
+                       done();
+               },
+               function() {
+                       assert.ok( true, "Rejected, solitary, non-Deferred thenable rejected properly" );
+                       done();
+               }
+       );
+} );
+
+QUnit.test( "jQuery.when does not reuse a solitary jQuery Deferred (gh-2018)", function( assert ) {
+
+       assert.expect( 2 );
+       var defer = jQuery.Deferred().resolve(),
+               promise = jQuery.when( defer );
+
+       assert.equal( promise.state(), "resolved", "Master Deferred is immediately resolved" );
+       assert.notStrictEqual( defer.promise(), promise, "jQuery.when returns the master deferred's promise" );
+} );