mirror of
https://github.com/jquery/jquery.git
synced 2024-11-23 02:54:22 +00:00
Deferred: Always handle progress callbacks before done/fail
Fixes gh-2013
Fixes gh-2010
Closes gh-2210
(cherry picked from commit 002240a6eb
)
This commit is contained in:
parent
0de798d6c2
commit
35295f1c20
@ -15,13 +15,14 @@ jQuery.extend({
|
|||||||
|
|
||||||
Deferred: function( func ) {
|
Deferred: function( func ) {
|
||||||
var tuples = [
|
var tuples = [
|
||||||
// action, add listener, callbacks, .then handlers, final state
|
// action, add listener, callbacks,
|
||||||
[ "resolve", "done", jQuery.Callbacks("once memory"),
|
// ... .then handlers, argument index, [final state]
|
||||||
jQuery.Callbacks("once memory"), "resolved" ],
|
|
||||||
[ "reject", "fail", jQuery.Callbacks("once memory"),
|
|
||||||
jQuery.Callbacks("once memory"), "rejected" ],
|
|
||||||
[ "notify", "progress", jQuery.Callbacks("memory"),
|
[ "notify", "progress", jQuery.Callbacks("memory"),
|
||||||
jQuery.Callbacks("memory") ]
|
jQuery.Callbacks("memory"), 2 ],
|
||||||
|
[ "resolve", "done", jQuery.Callbacks("once memory"),
|
||||||
|
jQuery.Callbacks("once memory"), 0, "resolved" ],
|
||||||
|
[ "reject", "fail", jQuery.Callbacks("once memory"),
|
||||||
|
jQuery.Callbacks("once memory"), 1, "rejected" ]
|
||||||
],
|
],
|
||||||
state = "pending",
|
state = "pending",
|
||||||
promise = {
|
promise = {
|
||||||
@ -38,17 +39,19 @@ jQuery.extend({
|
|||||||
|
|
||||||
return jQuery.Deferred(function( newDefer ) {
|
return jQuery.Deferred(function( newDefer ) {
|
||||||
jQuery.each( tuples, function( i, tuple ) {
|
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.done(function() { bind to newDefer or newDefer.resolve })
|
||||||
// deferred.fail(function() { bind to newDefer or newDefer.reject })
|
// deferred.fail(function() { bind to newDefer or newDefer.reject })
|
||||||
// deferred.progress(function() { bind to newDefer or newDefer.notify })
|
|
||||||
deferred[ tuple[1] ](function() {
|
deferred[ tuple[1] ](function() {
|
||||||
var returned = fn && fn.apply( this, arguments );
|
var returned = fn && fn.apply( this, arguments );
|
||||||
if ( returned && jQuery.isFunction( returned.promise ) ) {
|
if ( returned && jQuery.isFunction( returned.promise ) ) {
|
||||||
returned.promise()
|
returned.promise()
|
||||||
|
.progress( newDefer.notify )
|
||||||
.done( newDefer.resolve )
|
.done( newDefer.resolve )
|
||||||
.fail( newDefer.reject )
|
.fail( newDefer.reject );
|
||||||
.progress( newDefer.notify );
|
|
||||||
} else {
|
} else {
|
||||||
newDefer[ tuple[ 0 ] + "With" ](
|
newDefer[ tuple[ 0 ] + "With" ](
|
||||||
this === promise ? newDefer.promise() : this,
|
this === promise ? newDefer.promise() : this,
|
||||||
@ -176,8 +179,20 @@ jQuery.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return jQuery.Deferred(function( newDefer ) {
|
return jQuery.Deferred(function( newDefer ) {
|
||||||
// fulfilled_handlers.add( ... )
|
// progress_handlers.add( ... )
|
||||||
tuples[ 0 ][ 3 ].add(
|
tuples[ 0 ][ 3 ].add(
|
||||||
|
resolve(
|
||||||
|
0,
|
||||||
|
newDefer,
|
||||||
|
jQuery.isFunction( onProgress ) ?
|
||||||
|
onProgress :
|
||||||
|
Identity,
|
||||||
|
newDefer.notifyWith
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// fulfilled_handlers.add( ... )
|
||||||
|
tuples[ 1 ][ 3 ].add(
|
||||||
resolve(
|
resolve(
|
||||||
0,
|
0,
|
||||||
newDefer,
|
newDefer,
|
||||||
@ -188,7 +203,7 @@ jQuery.extend({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// rejected_handlers.add( ... )
|
// rejected_handlers.add( ... )
|
||||||
tuples[ 1 ][ 3 ].add(
|
tuples[ 2 ][ 3 ].add(
|
||||||
resolve(
|
resolve(
|
||||||
0,
|
0,
|
||||||
newDefer,
|
newDefer,
|
||||||
@ -197,18 +212,6 @@ jQuery.extend({
|
|||||||
Thrower
|
Thrower
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// progress_handlers.add( ... )
|
|
||||||
tuples[ 2 ][ 3 ].add(
|
|
||||||
resolve(
|
|
||||||
0,
|
|
||||||
newDefer,
|
|
||||||
jQuery.isFunction( onProgress ) ?
|
|
||||||
onProgress :
|
|
||||||
Identity,
|
|
||||||
newDefer.notifyWith
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}).promise();
|
}).promise();
|
||||||
},
|
},
|
||||||
// Get a promise for this deferred
|
// Get a promise for this deferred
|
||||||
@ -222,11 +225,11 @@ jQuery.extend({
|
|||||||
// Add list-specific methods
|
// Add list-specific methods
|
||||||
jQuery.each( tuples, function( i, tuple ) {
|
jQuery.each( tuples, function( i, tuple ) {
|
||||||
var list = tuple[ 2 ],
|
var list = tuple[ 2 ],
|
||||||
stateString = tuple[ 4 ];
|
stateString = tuple[ 5 ];
|
||||||
|
|
||||||
|
// promise.progress = list.add
|
||||||
// promise.done = list.add
|
// promise.done = list.add
|
||||||
// promise.fail = list.add
|
// promise.fail = list.add
|
||||||
// promise.progress = list.add
|
|
||||||
promise[ tuple[1] ] = list.add;
|
promise[ tuple[1] ] = list.add;
|
||||||
|
|
||||||
// Handle state
|
// Handle state
|
||||||
@ -240,29 +243,29 @@ jQuery.extend({
|
|||||||
|
|
||||||
// rejected_callbacks.disable
|
// rejected_callbacks.disable
|
||||||
// fulfilled_callbacks.disable
|
// fulfilled_callbacks.disable
|
||||||
tuples[ i ^ 1 ][ 2 ].disable,
|
tuples[ 3 - i ][ 2 ].disable,
|
||||||
|
|
||||||
// progress_callbacks.lock
|
// progress_callbacks.lock
|
||||||
tuples[ 2 ][ 2 ].lock
|
tuples[ 0 ][ 2 ].lock
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// progress_handlers.fire
|
||||||
// fulfilled_handlers.fire
|
// fulfilled_handlers.fire
|
||||||
// rejected_handlers.fire
|
// rejected_handlers.fire
|
||||||
// progress_handlers.fire
|
|
||||||
list.add( tuple[ 3 ].fire );
|
list.add( tuple[ 3 ].fire );
|
||||||
|
|
||||||
|
// deferred.notify = function() { deferred.notifyWith(...) }
|
||||||
// deferred.resolve = function() { deferred.resolveWith(...) }
|
// deferred.resolve = function() { deferred.resolveWith(...) }
|
||||||
// deferred.reject = function() { deferred.rejectWith(...) }
|
// deferred.reject = function() { deferred.rejectWith(...) }
|
||||||
// deferred.notify = function() { deferred.notifyWith(...) }
|
|
||||||
deferred[ tuple[0] ] = function() {
|
deferred[ tuple[0] ] = function() {
|
||||||
deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
|
deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// deferred.notifyWith = list.fireWith
|
||||||
// deferred.resolveWith = list.fireWith
|
// deferred.resolveWith = list.fireWith
|
||||||
// deferred.rejectWith = list.fireWith
|
// deferred.rejectWith = list.fireWith
|
||||||
// deferred.notifyWith = list.fireWith
|
|
||||||
deferred[ tuple[0] + "With" ] = list.fireWith;
|
deferred[ tuple[0] + "With" ] = list.fireWith;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -565,6 +565,54 @@ test( "jQuery.Deferred.then - progress and thenables", function( assert ) {
|
|||||||
trigger.notify();
|
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() {
|
test( "jQuery.when", function() {
|
||||||
|
|
||||||
expect( 37 );
|
expect( 37 );
|
||||||
|
Loading…
Reference in New Issue
Block a user