mirror of
https://github.com/jquery/jquery.git
synced 2024-11-23 02:54:22 +00:00
Deferred: Separate the two paths in jQuery.when
Single- and no-argument calls act like Promise.resolve. Multi-argument calls act like Promise.all. Fixes gh-3029 Closes gh-3059
This commit is contained in:
parent
0bd98b1b13
commit
356a3bccb0
@ -4,10 +4,20 @@ module.exports = function( grunt ) {
|
||||
|
||||
var spawnTest = require( "./lib/spawn_test.js" );
|
||||
|
||||
grunt.registerTask( "promises_aplus_tests", function() {
|
||||
grunt.registerTask( "promises_aplus_tests",
|
||||
[ "promises_aplus_tests_deferred", "promises_aplus_tests_when" ] );
|
||||
|
||||
grunt.registerTask( "promises_aplus_tests_deferred", function() {
|
||||
spawnTest( this.async(),
|
||||
"./node_modules/.bin/promises-aplus-tests",
|
||||
"test/promises_aplus_adapter.js"
|
||||
"test/promises_aplus_adapter_deferred.js"
|
||||
);
|
||||
} );
|
||||
|
||||
grunt.registerTask( "promises_aplus_tests_when", function() {
|
||||
spawnTest( this.async(),
|
||||
"./node_modules/.bin/promises-aplus-tests",
|
||||
"test/promises_aplus_adapter_when.js"
|
||||
);
|
||||
} );
|
||||
};
|
||||
|
100
src/deferred.js
100
src/deferred.js
@ -13,6 +13,38 @@ function Thrower( ex ) {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
function adoptValue( value, resolve, reject ) {
|
||||
var method;
|
||||
|
||||
try {
|
||||
|
||||
// Check for promise aspect first to privilege synchronous behavior
|
||||
if ( value && jQuery.isFunction( ( method = value.promise ) ) ) {
|
||||
method.call( value ).done( resolve ).fail( reject );
|
||||
|
||||
// Other thenables
|
||||
} else if ( value && jQuery.isFunction( ( method = value.then ) ) ) {
|
||||
method.call( value, resolve, reject );
|
||||
|
||||
// Other non-thenables
|
||||
} else {
|
||||
|
||||
// Support: Android 4.0 only
|
||||
// Strict mode functions invoked without .call/.apply get global-object context
|
||||
resolve.call( undefined, value );
|
||||
}
|
||||
|
||||
// For Promises/A+, convert exceptions into rejections
|
||||
// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
|
||||
// Deferred#then to conditionally suppress rejection.
|
||||
} catch ( /*jshint -W002 */ value ) {
|
||||
|
||||
// Support: Android 4.0 only
|
||||
// Strict mode functions invoked without .call/.apply get global-object context
|
||||
reject.call( undefined, value );
|
||||
}
|
||||
}
|
||||
|
||||
jQuery.extend( {
|
||||
|
||||
Deferred: function( func ) {
|
||||
@ -305,67 +337,45 @@ jQuery.extend( {
|
||||
},
|
||||
|
||||
// Deferred helper
|
||||
when: function() {
|
||||
var method, resolveContexts,
|
||||
i = 0,
|
||||
when: function( singleValue ) {
|
||||
var
|
||||
|
||||
// count of uncompleted subordinates
|
||||
remaining = arguments.length,
|
||||
|
||||
// count of unprocessed arguments
|
||||
i = remaining,
|
||||
|
||||
// subordinate fulfillment data
|
||||
resolveContexts = Array( i ),
|
||||
resolveValues = slice.call( arguments ),
|
||||
length = resolveValues.length,
|
||||
|
||||
// the count of uncompleted subordinates
|
||||
remaining = length,
|
||||
|
||||
// the master Deferred.
|
||||
// the master Deferred
|
||||
master = jQuery.Deferred(),
|
||||
|
||||
// Update function for both resolving subordinates
|
||||
// subordinate callback factory
|
||||
updateFunc = function( i ) {
|
||||
return function( value ) {
|
||||
resolveContexts[ i ] = this;
|
||||
resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
|
||||
if ( !( --remaining ) ) {
|
||||
master.resolveWith(
|
||||
resolveContexts.length === 1 ? resolveContexts[ 0 ] : resolveContexts,
|
||||
resolveValues
|
||||
);
|
||||
master.resolveWith( resolveContexts, resolveValues );
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Add listeners to promise-like subordinates; treat others as resolved
|
||||
if ( length > 0 ) {
|
||||
resolveContexts = new Array( length );
|
||||
for ( ; i < length; i++ ) {
|
||||
// Single- and empty arguments are adopted like Promise.resolve
|
||||
if ( remaining <= 1 ) {
|
||||
adoptValue( singleValue, master.resolve, master.reject );
|
||||
|
||||
// jQuery.Deferred - treated specially to get resolve-sync behavior
|
||||
if ( resolveValues[ i ] &&
|
||||
jQuery.isFunction( ( method = resolveValues[ i ].promise ) ) ) {
|
||||
|
||||
method.call( resolveValues[ i ] )
|
||||
.done( updateFunc( i ) )
|
||||
.fail( master.reject );
|
||||
|
||||
// Other thenables
|
||||
} else if ( resolveValues[ i ] &&
|
||||
jQuery.isFunction( ( method = resolveValues[ i ].then ) ) ) {
|
||||
|
||||
method.call(
|
||||
resolveValues[ i ],
|
||||
updateFunc( i ),
|
||||
master.reject
|
||||
);
|
||||
} else {
|
||||
|
||||
// Support: Android 4.0 only
|
||||
// Strict mode functions invoked without .call/.apply get global-object context
|
||||
updateFunc( i ).call( undefined, resolveValues[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
// If we're not waiting on anything, resolve the master
|
||||
} else {
|
||||
master.resolveWith();
|
||||
// Use .then() to unwrap secondary thenables (cf. gh-3000)
|
||||
return master.then();
|
||||
}
|
||||
|
||||
// Multiple arguments are aggregated like Promise.all array elements
|
||||
while ( i-- ) {
|
||||
adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
|
||||
}
|
||||
return master.promise();
|
||||
}
|
||||
} );
|
||||
|
51
test/promises_aplus_adapter_when.js
Normal file
51
test/promises_aplus_adapter_when.js
Normal file
@ -0,0 +1,51 @@
|
||||
/* jshint node: true */
|
||||
|
||||
"use strict";
|
||||
|
||||
require( "jsdom" ).env( "", function( errors, window ) {
|
||||
if ( errors ) {
|
||||
console.error( errors );
|
||||
return;
|
||||
}
|
||||
|
||||
var jQuery = require( ".." )( window );
|
||||
|
||||
exports.deferred = function() {
|
||||
var adopted, promised,
|
||||
obj = {
|
||||
resolve: function() {
|
||||
if ( !adopted ) {
|
||||
adopted = jQuery.when.apply( jQuery, arguments );
|
||||
if ( promised ) {
|
||||
adopted.then( promised.resolve, promised.reject );
|
||||
}
|
||||
}
|
||||
return adopted;
|
||||
},
|
||||
reject: function( value ) {
|
||||
if ( !adopted ) {
|
||||
adopted = jQuery.when( jQuery.Deferred().reject( value ) );
|
||||
if ( promised ) {
|
||||
adopted.then( promised.resolve, promised.reject );
|
||||
}
|
||||
}
|
||||
return adopted;
|
||||
},
|
||||
|
||||
// A manually-constructed thenable that works even if calls precede resolve/reject
|
||||
promise: {
|
||||
then: function() {
|
||||
if ( !adopted ) {
|
||||
if ( !promised ) {
|
||||
promised = jQuery.Deferred();
|
||||
}
|
||||
return promised.then.apply( promised, arguments );
|
||||
}
|
||||
return adopted.then.apply( adopted, arguments );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return obj;
|
||||
};
|
||||
} );
|
@ -761,11 +761,30 @@ QUnit.test( "jQuery.Deferred - notify and resolve", function( assert ) {
|
||||
} );
|
||||
} );
|
||||
|
||||
QUnit.test( "jQuery.when", function( assert ) {
|
||||
|
||||
assert.expect( 37 );
|
||||
QUnit.test( "jQuery.when(nonThenable) - like Promise.resolve", function( assert ) {
|
||||
"use strict";
|
||||
|
||||
assert.expect( 44 );
|
||||
|
||||
var
|
||||
|
||||
// Support: Android 4.0 only
|
||||
// Strict mode functions invoked without .call/.apply get global-object context
|
||||
defaultContext = (function getDefaultContext() { return this; }).call(),
|
||||
|
||||
done = assert.async( 20 );
|
||||
|
||||
jQuery.when()
|
||||
.done( function( resolveValue ) {
|
||||
assert.strictEqual( resolveValue, undefined, "Resolved .done with no arguments" );
|
||||
assert.strictEqual( this, defaultContext, "Default .done context with no arguments" );
|
||||
} )
|
||||
.then( function( resolveValue ) {
|
||||
assert.strictEqual( resolveValue, undefined, "Resolved .then with no arguments" );
|
||||
assert.strictEqual( this, defaultContext, "Default .then context with no arguments" );
|
||||
} );
|
||||
|
||||
// Some other objects
|
||||
jQuery.each( {
|
||||
"an empty string": "",
|
||||
"a non-empty string": "some string",
|
||||
@ -778,51 +797,136 @@ QUnit.test( "jQuery.when", function( assert ) {
|
||||
"a plain object": {},
|
||||
"an array": [ 1, 2, 3 ]
|
||||
}, function( message, value ) {
|
||||
assert.ok(
|
||||
jQuery.isFunction(
|
||||
jQuery.when( value ).done( function( resolveValue ) {
|
||||
assert.strictEqual( this, window, "Context is the global object with " + message );
|
||||
assert.strictEqual( resolveValue, value, "Test the promise was resolved with " + message );
|
||||
} ).promise
|
||||
),
|
||||
"Test " + message + " triggers the creation of a new Promise"
|
||||
);
|
||||
} );
|
||||
|
||||
assert.ok(
|
||||
jQuery.isFunction(
|
||||
jQuery.when().done( function( resolveValue ) {
|
||||
assert.strictEqual( this, window, "Test the promise was resolved with window as its context" );
|
||||
assert.strictEqual( resolveValue, undefined, "Test the promise was resolved with no parameter" );
|
||||
} ).promise
|
||||
),
|
||||
"Test calling when with no parameter triggers the creation of a new Promise"
|
||||
);
|
||||
|
||||
var cache,
|
||||
context = {};
|
||||
|
||||
jQuery.when( jQuery.Deferred().resolveWith( context ) ).done( function() {
|
||||
assert.strictEqual( this, context, "when( promise ) propagates context" );
|
||||
} );
|
||||
|
||||
jQuery.each( [ 1, 2, 3 ], function( k, i ) {
|
||||
jQuery.when( cache || jQuery.Deferred( function() {
|
||||
this.resolve( i );
|
||||
} )
|
||||
).done( function( value ) {
|
||||
assert.strictEqual( value, 1, "Function executed" + ( i > 1 ? " only once" : "" ) );
|
||||
cache = value;
|
||||
} );
|
||||
var code = "jQuery.when( " + message + " )",
|
||||
onFulfilled = function( method ) {
|
||||
var call = code + "." + method;
|
||||
return function( resolveValue ) {
|
||||
assert.strictEqual( resolveValue, value, call + " resolve" );
|
||||
assert.strictEqual( this, defaultContext, call + " context" );
|
||||
done();
|
||||
};
|
||||
},
|
||||
onRejected = function( method ) {
|
||||
var call = code + "." + method;
|
||||
return function() {
|
||||
assert.ok( false, call + " reject" );
|
||||
done();
|
||||
};
|
||||
};
|
||||
|
||||
jQuery.when( value )
|
||||
.done( onFulfilled( "done" ) )
|
||||
.fail( onRejected( "done" ) )
|
||||
.then( onFulfilled( "then" ), onRejected( "then" ) );
|
||||
} );
|
||||
} );
|
||||
|
||||
QUnit.test( "jQuery.when - joined", function( assert ) {
|
||||
QUnit.test( "jQuery.when(thenable) - like Promise.resolve", function( assert ) {
|
||||
"use strict";
|
||||
|
||||
assert.expect( 81 );
|
||||
assert.expect( 56 );
|
||||
|
||||
var deferreds = {
|
||||
var slice = [].slice,
|
||||
sentinel = { context: "explicit" },
|
||||
eventuallyFulfilled = jQuery.Deferred().notify( true ),
|
||||
eventuallyRejected = jQuery.Deferred().notify( true ),
|
||||
inputs = {
|
||||
promise: Promise.resolve( true ),
|
||||
rejectedPromise: Promise.reject( false ),
|
||||
deferred: jQuery.Deferred().resolve( true ),
|
||||
eventuallyFulfilled: eventuallyFulfilled,
|
||||
secondaryFulfilled: jQuery.Deferred().resolve( eventuallyFulfilled ),
|
||||
multiDeferred: jQuery.Deferred().resolve( "foo", "bar" ),
|
||||
deferredWith: jQuery.Deferred().resolveWith( sentinel, [ true ] ),
|
||||
multiDeferredWith: jQuery.Deferred().resolveWith( sentinel, [ "foo", "bar" ] ),
|
||||
rejectedDeferred: jQuery.Deferred().reject( false ),
|
||||
eventuallyRejected: eventuallyRejected,
|
||||
secondaryRejected: jQuery.Deferred().resolve( eventuallyRejected ),
|
||||
multiRejectedDeferred: jQuery.Deferred().reject( "baz", "quux" ),
|
||||
rejectedDeferredWith: jQuery.Deferred().rejectWith( sentinel, [ false ] ),
|
||||
multiRejectedDeferredWith: jQuery.Deferred().rejectWith( sentinel, [ "baz", "quux" ] )
|
||||
},
|
||||
contexts = {
|
||||
deferredWith: sentinel,
|
||||
multiDeferredWith: sentinel,
|
||||
rejectedDeferredWith: sentinel,
|
||||
multiRejectedDeferredWith: sentinel
|
||||
},
|
||||
willSucceed = {
|
||||
promise: [ true ],
|
||||
deferred: [ true ],
|
||||
eventuallyFulfilled: [ true ],
|
||||
secondaryFulfilled: [ true ],
|
||||
multiDeferred: [ "foo", "bar" ],
|
||||
deferredWith: [ true ],
|
||||
multiDeferredWith: [ "foo", "bar" ]
|
||||
},
|
||||
willError = {
|
||||
rejectedPromise: [ false ],
|
||||
rejectedDeferred: [ false ],
|
||||
eventuallyRejected: [ false ],
|
||||
secondaryRejected: [ false ],
|
||||
multiRejectedDeferred: [ "baz", "quux" ],
|
||||
rejectedDeferredWith: [ false ],
|
||||
multiRejectedDeferredWith: [ "baz", "quux" ]
|
||||
},
|
||||
|
||||
// Support: Android 4.0 only
|
||||
// Strict mode functions invoked without .call/.apply get global-object context
|
||||
defaultContext = (function getDefaultContext() { return this; }).call(),
|
||||
|
||||
done = assert.async( 28 );
|
||||
|
||||
jQuery.each( inputs, function( message, value ) {
|
||||
var code = "jQuery.when( " + message + " )",
|
||||
shouldResolve = willSucceed[ message ],
|
||||
shouldError = willError[ message ],
|
||||
context = contexts[ message ] || defaultContext,
|
||||
onFulfilled = function( method ) {
|
||||
var call = code + "." + method;
|
||||
return function() {
|
||||
if ( shouldResolve ) {
|
||||
assert.deepEqual( slice.call( arguments ), shouldResolve,
|
||||
call + " resolve" );
|
||||
assert.strictEqual( this, context, call + " context" );
|
||||
} else {
|
||||
assert.ok( false, call + " resolve" );
|
||||
}
|
||||
done();
|
||||
};
|
||||
},
|
||||
onRejected = function( method ) {
|
||||
var call = code + "." + method;
|
||||
return function() {
|
||||
if ( shouldError ) {
|
||||
assert.deepEqual( slice.call( arguments ), shouldError, call + " reject" );
|
||||
assert.strictEqual( this, context, call + " context" );
|
||||
} else {
|
||||
assert.ok( false, call + " reject" );
|
||||
}
|
||||
done();
|
||||
};
|
||||
};
|
||||
|
||||
jQuery.when( value )
|
||||
.done( onFulfilled( "done" ) )
|
||||
.fail( onRejected( "done" ) )
|
||||
.then( onFulfilled( "then" ), onRejected( "then" ) );
|
||||
} );
|
||||
|
||||
setTimeout( function() {
|
||||
eventuallyFulfilled.resolve( true );
|
||||
eventuallyRejected.reject( false );
|
||||
}, 50 );
|
||||
} );
|
||||
|
||||
QUnit.test( "jQuery.when(a, b) - like Promise.all", function( assert ) {
|
||||
"use strict";
|
||||
|
||||
assert.expect( 196 );
|
||||
|
||||
var slice = [].slice,
|
||||
deferreds = {
|
||||
rawValue: 1,
|
||||
fulfilled: jQuery.Deferred().resolve( 1 ),
|
||||
rejected: jQuery.Deferred().reject( 0 ),
|
||||
@ -842,46 +946,91 @@ QUnit.test( "jQuery.when - joined", function( assert ) {
|
||||
eventuallyRejected: true,
|
||||
rejectedStandardPromise: true
|
||||
},
|
||||
counter = 49,
|
||||
|
||||
// Support: Android 4.0 only
|
||||
// Strict mode functions invoked without .call/.apply get global-object context
|
||||
expectedContext = (function() { "use strict"; return this; }).call();
|
||||
defaultContext = (function getDefaultContext() { return this; }).call(),
|
||||
|
||||
QUnit.stop();
|
||||
done = assert.async( 98 );
|
||||
|
||||
function restart() {
|
||||
if ( !--counter ) {
|
||||
QUnit.start();
|
||||
}
|
||||
}
|
||||
|
||||
jQuery.each( deferreds, function( id1, defer1 ) {
|
||||
jQuery.each( deferreds, function( id2, defer2 ) {
|
||||
var shouldResolve = willSucceed[ id1 ] && willSucceed[ id2 ],
|
||||
jQuery.each( deferreds, function( id1, v1 ) {
|
||||
jQuery.each( deferreds, function( id2, v2 ) {
|
||||
var code = "jQuery.when( " + id1 + ", " + id2 + " )",
|
||||
shouldResolve = willSucceed[ id1 ] && willSucceed[ id2 ],
|
||||
shouldError = willError[ id1 ] || willError[ id2 ],
|
||||
expected = shouldResolve ? [ 1, 1 ] : [ 0, undefined ],
|
||||
code = "jQuery.when( " + id1 + ", " + id2 + " )";
|
||||
expected = shouldResolve ? [ 1, 1 ] : [ 0 ],
|
||||
context = shouldResolve ? [ defaultContext, defaultContext ] : defaultContext,
|
||||
onFulfilled = function( method ) {
|
||||
var call = code + "." + method;
|
||||
return function() {
|
||||
if ( shouldResolve ) {
|
||||
assert.deepEqual( slice.call( arguments ), expected,
|
||||
call + " resolve" );
|
||||
assert.deepEqual( this, context, code + " context" );
|
||||
} else {
|
||||
assert.ok( false, call + " resolve" );
|
||||
}
|
||||
done();
|
||||
};
|
||||
},
|
||||
onRejected = function( method ) {
|
||||
var call = code + "." + method;
|
||||
return function() {
|
||||
if ( shouldError ) {
|
||||
assert.deepEqual( slice.call( arguments ), expected, call + " reject" );
|
||||
assert.deepEqual( this, context, code + " context" );
|
||||
} else {
|
||||
assert.ok( false, call + " reject" );
|
||||
}
|
||||
done();
|
||||
};
|
||||
};
|
||||
|
||||
jQuery.when( defer1, defer2 ).done( function( a, b ) {
|
||||
if ( shouldResolve ) {
|
||||
assert.deepEqual( [ a, b ], expected, code + " => resolve" );
|
||||
assert.strictEqual( this[ 0 ], expectedContext, code + " => context[0] OK" );
|
||||
assert.strictEqual( this[ 1 ], expectedContext, code + " => context[1] OK" );
|
||||
} else {
|
||||
assert.ok( false, code + " => resolve" );
|
||||
}
|
||||
} ).fail( function( a, b ) {
|
||||
if ( shouldError ) {
|
||||
assert.deepEqual( [ a, b ], expected, code + " => reject" );
|
||||
} else {
|
||||
assert.ok( false, code + " => reject" );
|
||||
}
|
||||
} ).always( restart );
|
||||
jQuery.when( v1, v2 )
|
||||
.done( onFulfilled( "done" ) )
|
||||
.fail( onRejected( "done" ) )
|
||||
.then( onFulfilled( "then" ), onRejected( "then" ) );
|
||||
} );
|
||||
} );
|
||||
|
||||
setTimeout( function() {
|
||||
deferreds.eventuallyFulfilled.resolve( 1 );
|
||||
deferreds.eventuallyRejected.reject( 0 );
|
||||
}, 50 );
|
||||
} );
|
||||
|
||||
QUnit.test( "jQuery.when - always returns a new promise", function( assert ) {
|
||||
|
||||
assert.expect( 42 );
|
||||
|
||||
jQuery.each( {
|
||||
"no arguments": [],
|
||||
"non-thenable": [ "foo" ],
|
||||
"promise": [ Promise.resolve( "bar" ) ],
|
||||
"rejected promise": [ Promise.reject( "bar" ) ],
|
||||
"deferred": [ jQuery.Deferred().resolve( "baz" ) ],
|
||||
"rejected deferred": [ jQuery.Deferred().reject( "baz" ) ],
|
||||
"multi-resolved deferred": [ jQuery.Deferred().resolve( "qux", "quux" ) ],
|
||||
"multiple non-thenables": [ "corge", "grault" ],
|
||||
"multiple deferreds": [
|
||||
jQuery.Deferred().resolve( "garply" ),
|
||||
jQuery.Deferred().resolve( "waldo" )
|
||||
]
|
||||
}, function( label, args ) {
|
||||
var result = jQuery.when.apply( jQuery, args );
|
||||
|
||||
assert.ok( jQuery.isFunction( result.then ), "Thenable returned from " + label );
|
||||
assert.strictEqual( result.resolve, undefined, "Non-deferred returned from " + label );
|
||||
assert.strictEqual( result.promise(), result, "Promise returned from " + label );
|
||||
|
||||
jQuery.each( args, function( i, arg ) {
|
||||
assert.notStrictEqual( result, arg, "Returns distinct from arg " + i + " of " + label );
|
||||
if ( arg.promise ) {
|
||||
assert.notStrictEqual( result, arg.promise(),
|
||||
"Returns distinct from promise of arg " + i + " of " + label );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
deferreds.eventuallyFulfilled.resolve( 1 );
|
||||
deferreds.eventuallyRejected.reject( 0 );
|
||||
} );
|
||||
|
||||
QUnit.test( "jQuery.when - notify does not affect resolved", function( assert ) {
|
||||
@ -900,107 +1049,3 @@ QUnit.test( "jQuery.when - notify does not affect resolved", function( assert )
|
||||
assert.ok( false, "Error on resolve" );
|
||||
} );
|
||||
} );
|
||||
|
||||
QUnit.test( "jQuery.when - filtering", function( assert ) {
|
||||
|
||||
assert.expect( 2 );
|
||||
|
||||
function increment( x ) {
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
QUnit.stop();
|
||||
|
||||
jQuery.when(
|
||||
jQuery.Deferred().resolve( 3 ).then( increment ),
|
||||
jQuery.Deferred().reject( 5 ).then( null, increment )
|
||||
).done( function( four, six ) {
|
||||
assert.strictEqual( four, 4, "resolved value incremented" );
|
||||
assert.strictEqual( six, 6, "rejected value incremented" );
|
||||
QUnit.start();
|
||||
} );
|
||||
} );
|
||||
|
||||
QUnit.test( "jQuery.when - exceptions", function( assert ) {
|
||||
|
||||
assert.expect( 2 );
|
||||
|
||||
function woops() {
|
||||
throw "exception thrown";
|
||||
}
|
||||
|
||||
QUnit.stop();
|
||||
|
||||
jQuery.Deferred().resolve().then( woops ).fail( function( doneException ) {
|
||||
assert.strictEqual( doneException, "exception thrown", "throwing in done handler" );
|
||||
jQuery.Deferred().reject().then( null, woops ).fail( function( failException ) {
|
||||
assert.strictEqual( failException, "exception thrown", "throwing in fail handler" );
|
||||
QUnit.start();
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
||||
QUnit.test( "jQuery.when - chaining", function( assert ) {
|
||||
|
||||
assert.expect( 4 );
|
||||
|
||||
var defer = jQuery.Deferred();
|
||||
|
||||
function chain() {
|
||||
return defer;
|
||||
}
|
||||
|
||||
function chainStandard() {
|
||||
return Promise.resolve( "std deferred" );
|
||||
}
|
||||
|
||||
QUnit.stop();
|
||||
|
||||
jQuery.when(
|
||||
jQuery.Deferred().resolve( 3 ).then( chain ),
|
||||
jQuery.Deferred().reject( 5 ).then( null, chain ),
|
||||
jQuery.Deferred().resolve( 3 ).then( chainStandard ),
|
||||
jQuery.Deferred().reject( 5 ).then( null, chainStandard )
|
||||
).done( function( v1, v2, s1, s2 ) {
|
||||
assert.strictEqual( v1, "other deferred", "chaining in done handler" );
|
||||
assert.strictEqual( v2, "other deferred", "chaining in fail handler" );
|
||||
assert.strictEqual( s1, "std deferred", "chaining thenable in done handler" );
|
||||
assert.strictEqual( s2, "std deferred", "chaining thenable in fail handler" );
|
||||
QUnit.start();
|
||||
} );
|
||||
|
||||
defer.resolve( "other deferred" );
|
||||
} );
|
||||
|
||||
QUnit.test( "jQuery.when - solitary thenables", function( assert ) {
|
||||
|
||||
assert.expect( 1 );
|
||||
|
||||
var done = assert.async(),
|
||||
rejected = new Promise( function( resolve, reject ) {
|
||||
setTimeout( function() {
|
||||
reject( "rejected" );
|
||||
}, 100 );
|
||||
} );
|
||||
|
||||
jQuery.when( rejected ).then(
|
||||
function() {
|
||||
assert.ok( false, "Rejected, solitary, non-Deferred thenable should not resolve" );
|
||||
done();
|
||||
},
|
||||
function() {
|
||||
assert.ok( true, "Rejected, solitary, non-Deferred thenable rejected properly" );
|
||||
done();
|
||||
}
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( "jQuery.when does not reuse a solitary jQuery Deferred (gh-2018)", function( assert ) {
|
||||
|
||||
assert.expect( 2 );
|
||||
var defer = jQuery.Deferred().resolve(),
|
||||
promise = jQuery.when( defer );
|
||||
|
||||
assert.equal( promise.state(), "resolved", "Master Deferred is immediately resolved" );
|
||||
assert.notStrictEqual( defer.promise(), promise, "jQuery.when returns the master deferred's promise" );
|
||||
} );
|
||||
|
2
test/unit/effects.js
vendored
2
test/unit/effects.js
vendored
@ -1028,7 +1028,7 @@ jQuery.each( {
|
||||
jQuery( elem ).remove();
|
||||
|
||||
} );
|
||||
this.clock.tick( 50 );
|
||||
this.clock.tick( 100 );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
Loading…
Reference in New Issue
Block a user