Deferred cannot be cancelled by returning false in a callback. Exception in the callb...
authorunknown <Julian@.(none)>
Sat, 25 Dec 2010 00:29:04 +0000 (01:29 +0100)
committerunknown <Julian@.(none)>
Sat, 25 Dec 2010 00:29:04 +0000 (01:29 +0100)
src/core.js
test/unit/core.js

index 77d35bd..57a42d0 100644 (file)
@@ -805,10 +805,7 @@ jQuery.extend({
        },
        
        // Create a simple deferred (one callbacks list)
-       _Deferred: function( cancellable ) {
-               
-               // cancellable by default
-               cancellable = cancellable !== false;
+       _Deferred: function() {
                
                var // callbacks list
                        callbacks = [],
@@ -825,7 +822,7 @@ jQuery.extend({
                                then: function () {
                                        
                                        if ( ! cancelled ) {
-                                       
+                                               
                                                var args = arguments,
                                                        i,
                                                        length,
@@ -852,24 +849,23 @@ jQuery.extend({
                                                        deferred.fire( _fired[ 0 ] , _fired[ 1 ] );
                                                }
                                        }
+                                       
                                        return this;
                                },
                                
                                // resolve with given context and args
-                               // (i is used internally)
-                               fire: function( context , args , i ) {
+                               fire: function( context , args ) {
                                        if ( ! cancelled && ! fired && ! firing ) {
+                                               
                                                firing = 1;
+                                               
                                                try {
-                                                       for( i = 0 ; ! cancelled && callbacks[ i ] ; i++ ) {
-                                                               cancelled = ( callbacks[ i ].apply( context , args ) === false ) && cancellable;
+                                                       while( callbacks[ 0 ] ) {
+                                                               callbacks.shift().apply( context , args );
                                                        }
-                                               } catch( e ) {
-                                                       cancelled = cancellable;
-                                                       jQuery.error( e );
-                                               } finally {
+                                               }
+                                               finally {
                                                        fired = [ context , args ];
-                                                       callbacks = cancelled ? [] : callbacks.slice( i + 1 );
                                                        firing = 0;
                                                }
                                        }
@@ -882,15 +878,22 @@ jQuery.extend({
                                        return this;
                                },
                                
-                               // cancelling further callbacks
+                               // Has this deferred been resolved?
+                               isResolved: function() {
+                                       return !!( firing || fired );
+                               },
+                               
+                               // Cancel
                                cancel: function() {
-                                       if ( cancellable ) {
-                                               callbacks = [];
-                                               cancelled = 1;
-                                       }
+                                       cancelled = 1;
+                                       callbacks = [];
                                        return this;
-                               }
+                               },
                                
+                               // Has this deferred been cancelled?
+                               isCancelled: function() {
+                                       return !!cancelled;
+                               }
                        };
                
                // Add the deferred marker
@@ -901,21 +904,11 @@ jQuery.extend({
        
        // Full fledged deferred (two callbacks list)
        // Typical success/error system
-       Deferred: function( func , cancellable ) {
-               
-               // Handle varargs
-               if ( arguments.length === 1 ) {
-                       
-                       if ( typeof func === "boolean" ) {
-                               cancellable = func;
-                               func = 0;
-                       }
-               }
+       Deferred: function( func ) {
                
-               var errorDeferred = jQuery._Deferred( cancellable ),
-                       deferred = jQuery._Deferred( cancellable ),
-                       // Keep reference of the cancel method since we'll redefine it
-                       cancelThen = deferred.cancel;
+               var errorDeferred = jQuery._Deferred(),
+                       deferred = jQuery._Deferred(),
+                       successCancel = deferred.cancel;
                        
                // Add errorDeferred methods and redefine cancel                        
                jQuery.extend( deferred , {
@@ -923,16 +916,16 @@ jQuery.extend({
                                fail: errorDeferred.then,
                                fireReject: errorDeferred.fire,
                                reject: errorDeferred.resolve,
-                               cancel: function() {
-                                       cancelThen();
-                                       errorDeferred.cancel();
-                                       return this;
-                               }
+                               isRejected: errorDeferred.isResolved
 
                } );
                
+               // Remove cancel related
+               delete deferred.cancel;
+               delete deferred.isCancelled;
+               
                // Make sure only one callback list will be used
-               deferred.then( errorDeferred.cancel ).fail( cancelThen );
+               deferred.then( errorDeferred.cancel ).fail( successCancel );
                
                // Call given func if any
                if ( func ) {
@@ -979,7 +972,7 @@ jQuery.extend({
 
 // Create readyList deferred
 // also force $.fn.ready to be recognized as a defer
-readyList = jQuery._Deferred( false );
+readyList = jQuery._Deferred();
 jQuery.fn.ready._ = deferredMarker;
 
 // Populate the class2type map
index 619ad92..8af59ff 100644 (file)
@@ -905,7 +905,7 @@ test("jQuery.parseJSON", function(){
 
 test("jQuery._Deferred()", function() {
        
-       expect( 14 );
+       expect( 10 );
        
        var deferred,
                object,
@@ -938,31 +938,19 @@ test("jQuery._Deferred()", function() {
        test = true;
        
        deferred.then( function() {
-               ok( false , "Manual cancel was ignored" );
+               ok( false , "Cancel was ignored" );
                test = false;
        } );
        
-       ok( test , "Test manual cancel" );
+       ok( test , "Test cancel" );
        
-       deferred = jQuery._Deferred().then( function() {
-               return false;
-       } );
-       
-       deferred.resolve();
+       deferred = jQuery._Deferred().resolve();
        
-       test = true;
-       
-       deferred.then( function() {
-               test = false;
-       } );
-       
-       ok( test , "Test cancel by returning false" );
-
        try {
-               deferred = jQuery._Deferred().resolve().then( function() {
+               deferred.then( function() {
                        throw "Error";
                } , function() {
-                       ok( false , "Test deferred cancel on exception" );
+                       ok( true , "Test deferred do not cancel on exception" );
                } );
        } catch( e ) {
                strictEqual( e , "Error" , "Test deferred propagates exceptions");
@@ -1001,28 +989,6 @@ test("jQuery._Deferred()", function() {
        
        strictEqual( test , "ABC" , "Test then callbacks order" );
        
-       deferred = jQuery._Deferred( false ).resolve().cancel();
-       
-       deferred.then( function() {
-               ok( true , "Test non-cancellable deferred not cancelled manually");
-               return false;
-       } );
-
-       deferred.then( function() {
-               ok( true , "Test non-cancellable deferred not cancelled by returning false");
-       } );
-       
-       try {
-               deferred.then( function() {
-                       throw "Error";
-               } , function() {
-                       ok( true , "Test non-cancellable deferred keeps callbacks after exception" );
-               } );
-       } catch( e ) {
-               strictEqual( e , "Error" , "Test non-cancellable deferred propagates exceptions");
-               deferred.then();
-       }
-       
        deferred = jQuery._Deferred();
        
        deferred.fire( jQuery , [ document ] ).then( function( doc ) {
@@ -1032,7 +998,7 @@ test("jQuery._Deferred()", function() {
 
 test("jQuery.Deferred()", function() {
        
-       expect( 8 );
+       expect( 4 );
        
        jQuery.Deferred( function( defer ) {
                strictEqual( this , defer , "Defer passed as this & first argument" );
@@ -1052,39 +1018,6 @@ test("jQuery.Deferred()", function() {
        }).fail( function() {
                ok( true , "Error on reject" );
        });
-       
-       var flag = true;
-       
-       jQuery.Deferred().resolve().cancel().then( function() {
-               ok( flag = false , "Success on resolve/cancel" );
-       }).fail( function() {
-               ok( flag = false , "Error on resolve/cancel" );
-       });
-       
-       ok( flag , "Cancel on resolve" );
-       
-       flag = true;
-       
-       jQuery.Deferred().reject().cancel().then( function() {
-               ok( flag = false , "Success on reject/cancel" );
-       }).fail( function() {
-               ok( flag = false , "Error on reject/cancel" );
-       });
-       
-       ok( flag , "Cancel on reject" );
-       
-       jQuery.Deferred( false ).resolve().then( function() {
-               return false;
-       } , function() {
-               ok( true , "Not cancelled on resolve" );
-       });
-       
-       jQuery.Deferred( false ).reject().fail( function() {
-               return false;
-       } , function() {
-               ok( true , "Not cancelled on reject" );
-       });
-       
 });
        
 test("jQuery.isDeferred()", function() {