]> source.dussan.org Git - jquery.git/commitdiff
Deferred: Always handle progress callbacks before done/fail
authorRichard Gibson <richard.gibson@gmail.com>
Tue, 14 Apr 2015 17:30:58 +0000 (13:30 -0400)
committerRichard Gibson <richard.gibson@gmail.com>
Wed, 22 Apr 2015 19:25:35 +0000 (15:25 -0400)
Fixes gh-2013
Fixes gh-2010
Closes gh-2210

(cherry picked from commit 002240a6eb1cee2fcd886d5cf44893eb67f246f1)

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

index a45dad88bfc25a55f087363d0300bcbcbbf54dc5..6ec9eec0677bacd8a0d594db468df373ce3582fd 100644 (file)
@@ -15,13 +15,14 @@ jQuery.extend({
 
        Deferred: function( func ) {
                var tuples = [
-                               // action, add listener, callbacks, .then handlers, final state
+                               // action, add listener, callbacks,
+                               // ... .then handlers, argument index, [final state]
+                               [ "notify", "progress", jQuery.Callbacks("memory"),
+                                       jQuery.Callbacks("memory"), 2 ],
                                [ "resolve", "done", jQuery.Callbacks("once memory"),
-                                       jQuery.Callbacks("once memory"), "resolved" ],
+                                       jQuery.Callbacks("once memory"), 0, "resolved" ],
                                [ "reject", "fail", jQuery.Callbacks("once memory"),
-                                       jQuery.Callbacks("once memory"), "rejected" ],
-                               [ "notify", "progress", jQuery.Callbacks("memory"),
-                                       jQuery.Callbacks("memory") ]
+                                       jQuery.Callbacks("once memory"), 1, "rejected" ]
                        ],
                        state = "pending",
                        promise = {
@@ -38,17 +39,19 @@ jQuery.extend({
 
                                        return jQuery.Deferred(function( newDefer ) {
                                                jQuery.each( tuples, function( i, tuple ) {
-                                                       var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+                                                       // Map tuples (progress, done, fail) to arguments (done, fail, progress)
+                                                       var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
+
+                                                       // deferred.progress(function() { bind to newDefer or newDefer.notify })
                                                        // deferred.done(function() { bind to newDefer or newDefer.resolve })
                                                        // deferred.fail(function() { bind to newDefer or newDefer.reject })
-                                                       // deferred.progress(function() { bind to newDefer or newDefer.notify })
                                                        deferred[ tuple[1] ](function() {
                                                                var returned = fn && fn.apply( this, arguments );
                                                                if ( returned && jQuery.isFunction( returned.promise ) ) {
                                                                        returned.promise()
+                                                                               .progress( newDefer.notify )
                                                                                .done( newDefer.resolve )
-                                                                               .fail( newDefer.reject )
-                                                                               .progress( newDefer.notify );
+                                                                               .fail( newDefer.reject );
                                                                } else {
                                                                        newDefer[ tuple[ 0 ] + "With" ](
                                                                                this === promise ? newDefer.promise() : this,
@@ -176,37 +179,37 @@ jQuery.extend({
                                        }
 
                                        return jQuery.Deferred(function( newDefer ) {
-                                               // fulfilled_handlers.add( ... )
+                                               // progress_handlers.add( ... )
                                                tuples[ 0 ][ 3 ].add(
                                                        resolve(
                                                                0,
                                                                newDefer,
-                                                               jQuery.isFunction( onFulfilled ) ?
-                                                                       onFulfilled :
-                                                                       Identity
+                                                               jQuery.isFunction( onProgress ) ?
+                                                                       onProgress :
+                                                                       Identity,
+                                                               newDefer.notifyWith
                                                        )
                                                );
 
-                                               // rejected_handlers.add( ... )
+                                               // fulfilled_handlers.add( ... )
                                                tuples[ 1 ][ 3 ].add(
                                                        resolve(
                                                                0,
                                                                newDefer,
-                                                               jQuery.isFunction( onRejected ) ?
-                                                                       onRejected :
-                                                                       Thrower
+                                                               jQuery.isFunction( onFulfilled ) ?
+                                                                       onFulfilled :
+                                                                       Identity
                                                        )
                                                );
 
-                                               // progress_handlers.add( ... )
+                                               // rejected_handlers.add( ... )
                                                tuples[ 2 ][ 3 ].add(
                                                        resolve(
                                                                0,
                                                                newDefer,
-                                                               jQuery.isFunction( onProgress ) ?
-                                                                       onProgress :
-                                                                       Identity,
-                                                               newDefer.notifyWith
+                                                               jQuery.isFunction( onRejected ) ?
+                                                                       onRejected :
+                                                                       Thrower
                                                        )
                                                );
                                        }).promise();
@@ -222,11 +225,11 @@ jQuery.extend({
                // Add list-specific methods
                jQuery.each( tuples, function( i, tuple ) {
                        var list = tuple[ 2 ],
-                               stateString = tuple[ 4 ];
+                               stateString = tuple[ 5 ];
 
+                       // promise.progress = list.add
                        // promise.done = list.add
                        // promise.fail = list.add
-                       // promise.progress = list.add
                        promise[ tuple[1] ] = list.add;
 
                        // Handle state
@@ -240,29 +243,29 @@ jQuery.extend({
 
                                        // rejected_callbacks.disable
                                        // fulfilled_callbacks.disable
-                                       tuples[ i ^ 1 ][ 2 ].disable,
+                                       tuples[ 3 - i ][ 2 ].disable,
 
                                        // progress_callbacks.lock
-                                       tuples[ 2 ][ 2 ].lock
+                                       tuples[ 0 ][ 2 ].lock
                                );
                        }
 
+                       // progress_handlers.fire
                        // fulfilled_handlers.fire
                        // rejected_handlers.fire
-                       // progress_handlers.fire
                        list.add( tuple[ 3 ].fire );
 
+                       // deferred.notify = function() { deferred.notifyWith(...) }
                        // deferred.resolve = function() { deferred.resolveWith(...) }
                        // deferred.reject = function() { deferred.rejectWith(...) }
-                       // deferred.notify = function() { deferred.notifyWith(...) }
                        deferred[ tuple[0] ] = function() {
                                deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
                                return this;
                        };
 
+                       // deferred.notifyWith = list.fireWith
                        // deferred.resolveWith = list.fireWith
                        // deferred.rejectWith = list.fireWith
-                       // deferred.notifyWith = list.fireWith
                        deferred[ tuple[0] + "With" ] = list.fireWith;
                });
 
index c2dcf33d0b89f499feaf5cd6f3ffb2511c30c895..97f9111dd35bab9e536f27458fb93c890b3e52c7 100644 (file)
@@ -565,6 +565,54 @@ test( "jQuery.Deferred.then - progress and thenables", function( assert ) {
        trigger.notify();
 });
 
+test( "jQuery.Deferred - notify and resolve", function( assert ) {
+
+       expect( 7 );
+
+       var notifiedResolved = jQuery.Deferred().notify( "foo" )/*xxx .resolve( "bar" )*/,
+               done = jQuery.map( new Array( 3 ), function() { return assert.async(); } );
+
+       notifiedResolved.progress( function( v ) {
+               assert.strictEqual( v, "foo", "progress value" );
+       } );
+
+       notifiedResolved.pipe().progress( function( v ) {
+               assert.strictEqual( v, "foo", "piped progress value" );
+       } );
+
+       notifiedResolved.pipe( null, null, function() {
+               return "baz";
+       } ).progress( function( v ) {
+               assert.strictEqual( v, "baz", "replaced piped progress value" );
+       } );
+
+       notifiedResolved.pipe( null, null, function() {
+               return jQuery.Deferred().notify( "baz" ).resolve( "quux" );
+       } ).progress( function( v ) {
+               assert.strictEqual( v, "baz", "deferred replaced piped progress value" );
+       } );
+
+       notifiedResolved.then().progress( function( v ) {
+               assert.strictEqual( v, "foo", "then'd progress value" );
+               done.pop().call();
+       } );
+
+       notifiedResolved.then( null, null, function() {
+               return "baz";
+       } ).progress( function( v ) {
+               assert.strictEqual( v, "baz", "replaced then'd progress value" );
+               done.pop().call();
+       } );
+
+       notifiedResolved.then( null, null, function() {
+               return jQuery.Deferred().notify( "baz" ).resolve( "quux" );
+       } ).progress( function( v ) {
+               // Progress from the surrogate deferred is ignored
+               assert.strictEqual( v, "quux", "deferred replaced then'd progress value" );
+               done.pop().call();
+       } );
+});
+
 test( "jQuery.when", function() {
 
        expect( 37 );