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.
This commit is contained in:
parent
fd63416ab1
commit
23d455b446
77
src/core.js
77
src/core.js
|
@ -805,10 +805,7 @@ jQuery.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Create a simple deferred (one callbacks list)
|
// Create a simple deferred (one callbacks list)
|
||||||
_Deferred: function( cancellable ) {
|
_Deferred: function() {
|
||||||
|
|
||||||
// cancellable by default
|
|
||||||
cancellable = cancellable !== false;
|
|
||||||
|
|
||||||
var // callbacks list
|
var // callbacks list
|
||||||
callbacks = [],
|
callbacks = [],
|
||||||
|
@ -852,24 +849,23 @@ jQuery.extend({
|
||||||
deferred.fire( _fired[ 0 ] , _fired[ 1 ] );
|
deferred.fire( _fired[ 0 ] , _fired[ 1 ] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
// resolve with given context and args
|
// resolve with given context and args
|
||||||
// (i is used internally)
|
fire: function( context , args ) {
|
||||||
fire: function( context , args , i ) {
|
|
||||||
if ( ! cancelled && ! fired && ! firing ) {
|
if ( ! cancelled && ! fired && ! firing ) {
|
||||||
|
|
||||||
firing = 1;
|
firing = 1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for( i = 0 ; ! cancelled && callbacks[ i ] ; i++ ) {
|
while( callbacks[ 0 ] ) {
|
||||||
cancelled = ( callbacks[ i ].apply( context , args ) === false ) && cancellable;
|
callbacks.shift().apply( context , args );
|
||||||
}
|
}
|
||||||
} catch( e ) {
|
}
|
||||||
cancelled = cancellable;
|
finally {
|
||||||
jQuery.error( e );
|
|
||||||
} finally {
|
|
||||||
fired = [ context , args ];
|
fired = [ context , args ];
|
||||||
callbacks = cancelled ? [] : callbacks.slice( i + 1 );
|
|
||||||
firing = 0;
|
firing = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -882,15 +878,22 @@ jQuery.extend({
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
// cancelling further callbacks
|
// Has this deferred been resolved?
|
||||||
cancel: function() {
|
isResolved: function() {
|
||||||
if ( cancellable ) {
|
return !!( firing || fired );
|
||||||
callbacks = [];
|
},
|
||||||
cancelled = 1;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Cancel
|
||||||
|
cancel: function() {
|
||||||
|
cancelled = 1;
|
||||||
|
callbacks = [];
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Has this deferred been cancelled?
|
||||||
|
isCancelled: function() {
|
||||||
|
return !!cancelled;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add the deferred marker
|
// Add the deferred marker
|
||||||
|
@ -901,21 +904,11 @@ jQuery.extend({
|
||||||
|
|
||||||
// Full fledged deferred (two callbacks list)
|
// Full fledged deferred (two callbacks list)
|
||||||
// Typical success/error system
|
// Typical success/error system
|
||||||
Deferred: function( func , cancellable ) {
|
Deferred: function( func ) {
|
||||||
|
|
||||||
// Handle varargs
|
var errorDeferred = jQuery._Deferred(),
|
||||||
if ( arguments.length === 1 ) {
|
deferred = jQuery._Deferred(),
|
||||||
|
successCancel = deferred.cancel;
|
||||||
if ( typeof func === "boolean" ) {
|
|
||||||
cancellable = func;
|
|
||||||
func = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var errorDeferred = jQuery._Deferred( cancellable ),
|
|
||||||
deferred = jQuery._Deferred( cancellable ),
|
|
||||||
// Keep reference of the cancel method since we'll redefine it
|
|
||||||
cancelThen = deferred.cancel;
|
|
||||||
|
|
||||||
// Add errorDeferred methods and redefine cancel
|
// Add errorDeferred methods and redefine cancel
|
||||||
jQuery.extend( deferred , {
|
jQuery.extend( deferred , {
|
||||||
|
@ -923,16 +916,16 @@ jQuery.extend({
|
||||||
fail: errorDeferred.then,
|
fail: errorDeferred.then,
|
||||||
fireReject: errorDeferred.fire,
|
fireReject: errorDeferred.fire,
|
||||||
reject: errorDeferred.resolve,
|
reject: errorDeferred.resolve,
|
||||||
cancel: function() {
|
isRejected: errorDeferred.isResolved
|
||||||
cancelThen();
|
|
||||||
errorDeferred.cancel();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// Remove cancel related
|
||||||
|
delete deferred.cancel;
|
||||||
|
delete deferred.isCancelled;
|
||||||
|
|
||||||
// Make sure only one callback list will be used
|
// 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
|
// Call given func if any
|
||||||
if ( func ) {
|
if ( func ) {
|
||||||
|
@ -979,7 +972,7 @@ jQuery.extend({
|
||||||
|
|
||||||
// Create readyList deferred
|
// Create readyList deferred
|
||||||
// also force $.fn.ready to be recognized as a defer
|
// also force $.fn.ready to be recognized as a defer
|
||||||
readyList = jQuery._Deferred( false );
|
readyList = jQuery._Deferred();
|
||||||
jQuery.fn.ready._ = deferredMarker;
|
jQuery.fn.ready._ = deferredMarker;
|
||||||
|
|
||||||
// Populate the class2type map
|
// Populate the class2type map
|
||||||
|
|
|
@ -907,7 +907,7 @@ test("jQuery.parseJSON", function(){
|
||||||
|
|
||||||
test("jQuery._Deferred()", function() {
|
test("jQuery._Deferred()", function() {
|
||||||
|
|
||||||
expect( 14 );
|
expect( 10 );
|
||||||
|
|
||||||
var deferred,
|
var deferred,
|
||||||
object,
|
object,
|
||||||
|
@ -940,31 +940,19 @@ test("jQuery._Deferred()", function() {
|
||||||
test = true;
|
test = true;
|
||||||
|
|
||||||
deferred.then( function() {
|
deferred.then( function() {
|
||||||
ok( false , "Manual cancel was ignored" );
|
ok( false , "Cancel was ignored" );
|
||||||
test = false;
|
test = false;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
ok( test , "Test manual cancel" );
|
ok( test , "Test cancel" );
|
||||||
|
|
||||||
deferred = jQuery._Deferred().then( function() {
|
deferred = jQuery._Deferred().resolve();
|
||||||
return false;
|
|
||||||
} );
|
|
||||||
|
|
||||||
deferred.resolve();
|
|
||||||
|
|
||||||
test = true;
|
|
||||||
|
|
||||||
deferred.then( function() {
|
|
||||||
test = false;
|
|
||||||
} );
|
|
||||||
|
|
||||||
ok( test , "Test cancel by returning false" );
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
deferred = jQuery._Deferred().resolve().then( function() {
|
deferred.then( function() {
|
||||||
throw "Error";
|
throw "Error";
|
||||||
} , function() {
|
} , function() {
|
||||||
ok( false , "Test deferred cancel on exception" );
|
ok( true , "Test deferred do not cancel on exception" );
|
||||||
} );
|
} );
|
||||||
} catch( e ) {
|
} catch( e ) {
|
||||||
strictEqual( e , "Error" , "Test deferred propagates exceptions");
|
strictEqual( e , "Error" , "Test deferred propagates exceptions");
|
||||||
|
@ -1003,28 +991,6 @@ test("jQuery._Deferred()", function() {
|
||||||
|
|
||||||
strictEqual( test , "ABC" , "Test then callbacks order" );
|
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 = jQuery._Deferred();
|
||||||
|
|
||||||
deferred.fire( jQuery , [ document ] ).then( function( doc ) {
|
deferred.fire( jQuery , [ document ] ).then( function( doc ) {
|
||||||
|
@ -1034,7 +1000,7 @@ test("jQuery._Deferred()", function() {
|
||||||
|
|
||||||
test("jQuery.Deferred()", function() {
|
test("jQuery.Deferred()", function() {
|
||||||
|
|
||||||
expect( 8 );
|
expect( 4 );
|
||||||
|
|
||||||
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" );
|
||||||
|
@ -1054,39 +1020,6 @@ test("jQuery.Deferred()", function() {
|
||||||
}).fail( function() {
|
}).fail( function() {
|
||||||
ok( true , "Error on reject" );
|
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() {
|
test("jQuery.isDeferred()", function() {
|
||||||
|
|
Loading…
Reference in a new issue