@@ -13,6 +13,38 @@ function Thrower( ex ) {
1313 throw ex ;
1414}
1515
16+ function adoptValue ( value , resolve , reject ) {
17+ var method ;
18+
19+ try {
20+
21+ // Check for promise aspect first to privilege synchronous behavior
22+ if ( value && jQuery . isFunction ( ( method = value . promise ) ) ) {
23+ method . call ( value ) . done ( resolve ) . fail ( reject ) ;
24+
25+ // Other thenables
26+ } else if ( value && jQuery . isFunction ( ( method = value . then ) ) ) {
27+ method . call ( value , resolve , reject ) ;
28+
29+ // Other non-thenables
30+ } else {
31+
32+ // Support: Android 4.0 only
33+ // Strict mode functions invoked without .call/.apply get global-object context
34+ resolve . call ( undefined , value ) ;
35+ }
36+
37+ // For Promises/A+, convert exceptions into rejections
38+ // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
39+ // Deferred#then to conditionally suppress rejection.
40+ } catch ( /*jshint -W002 */ value ) {
41+
42+ // Support: Android 4.0 only
43+ // Strict mode functions invoked without .call/.apply get global-object context
44+ reject . call ( undefined , value ) ;
45+ }
46+ }
47+
1648jQuery . extend ( {
1749
1850 Deferred : function ( func ) {
@@ -305,67 +337,45 @@ jQuery.extend( {
305337 } ,
306338
307339 // Deferred helper
308- when : function ( ) {
309- var method , resolveContexts ,
310- i = 0 ,
311- resolveValues = slice . call ( arguments ) ,
312- length = resolveValues . length ,
340+ when : function ( singleValue ) {
341+ var
342+
343+ // count of uncompleted subordinates
344+ remaining = arguments . length ,
313345
314- // the count of uncompleted subordinates
315- remaining = length ,
346+ // count of unprocessed arguments
347+ i = remaining ,
348+
349+ // subordinate fulfillment data
350+ resolveContexts = Array ( i ) ,
351+ resolveValues = slice . call ( arguments ) ,
316352
317- // the master Deferred.
353+ // the master Deferred
318354 master = jQuery . Deferred ( ) ,
319355
320- // Update function for both resolving subordinates
356+ // subordinate callback factory
321357 updateFunc = function ( i ) {
322358 return function ( value ) {
323359 resolveContexts [ i ] = this ;
324360 resolveValues [ i ] = arguments . length > 1 ? slice . call ( arguments ) : value ;
325361 if ( ! ( -- remaining ) ) {
326- master . resolveWith (
327- resolveContexts . length === 1 ? resolveContexts [ 0 ] : resolveContexts ,
328- resolveValues
329- ) ;
362+ master . resolveWith ( resolveContexts , resolveValues ) ;
330363 }
331364 } ;
332365 } ;
333366
334- // Add listeners to promise-like subordinates; treat others as resolved
335- if ( length > 0 ) {
336- resolveContexts = new Array ( length ) ;
337- for ( ; i < length ; i ++ ) {
338-
339- // jQuery.Deferred - treated specially to get resolve-sync behavior
340- if ( resolveValues [ i ] &&
341- jQuery . isFunction ( ( method = resolveValues [ i ] . promise ) ) ) {
342-
343- method . call ( resolveValues [ i ] )
344- . done ( updateFunc ( i ) )
345- . fail ( master . reject ) ;
346-
347- // Other thenables
348- } else if ( resolveValues [ i ] &&
349- jQuery . isFunction ( ( method = resolveValues [ i ] . then ) ) ) {
350-
351- method . call (
352- resolveValues [ i ] ,
353- updateFunc ( i ) ,
354- master . reject
355- ) ;
356- } else {
357-
358- // Support: Android 4.0 only
359- // Strict mode functions invoked without .call/.apply get global-object context
360- updateFunc ( i ) . call ( undefined , resolveValues [ i ] ) ;
361- }
362- }
367+ // Single- and empty arguments are adopted like Promise.resolve
368+ if ( remaining <= 1 ) {
369+ adoptValue ( singleValue , master . resolve , master . reject ) ;
363370
364- // If we're not waiting on anything, resolve the master
365- } else {
366- master . resolveWith ( ) ;
371+ // Use .then() to unwrap secondary thenables (cf. gh-3000)
372+ return master . then ( ) ;
367373 }
368374
375+ // Multiple arguments are aggregated like Promise.all array elements
376+ while ( i -- ) {
377+ adoptValue ( resolveValues [ i ] , updateFunc ( i ) , master . reject ) ;
378+ }
369379 return master . promise ( ) ;
370380 }
371381} ) ;
0 commit comments