From 846c52d1f8535a6283dcc42c6e8f0c26991936ad Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 25 Dec 2010 01:29:04 +0100 Subject: [PATCH] Deferred cannot be cancelled by returning false in a callback. Exception in the callback are still propagated and execution of remaining callbacks is still possible. --- src/core.js | 75 ++++++++++++++++++++----------------------- test/unit/core.js | 81 ++++------------------------------------------- 2 files changed, 41 insertions(+), 115 deletions(-) diff --git a/src/core.js b/src/core.js index 77d35bdd9..57a42d09e 100644 --- a/src/core.js +++ b/src/core.js @@ -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 diff --git a/test/unit/core.js b/test/unit/core.js index 619ad92bd..8af59ffbf 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -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() { -- 2.39.5