tuiHoneyPot

front and back end of my TUI honeypot
Log | Files | Refs | README

deferred.js (11376B)


      1 define( [
      2 	"./core",
      3 	"./var/isFunction",
      4 	"./var/slice",
      5 	"./callbacks"
      6 ], function( jQuery, isFunction, slice ) {
      7 
      8 "use strict";
      9 
     10 function Identity( v ) {
     11 	return v;
     12 }
     13 function Thrower( ex ) {
     14 	throw ex;
     15 }
     16 
     17 function adoptValue( value, resolve, reject, noValue ) {
     18 	var method;
     19 
     20 	try {
     21 
     22 		// Check for promise aspect first to privilege synchronous behavior
     23 		if ( value && isFunction( ( method = value.promise ) ) ) {
     24 			method.call( value ).done( resolve ).fail( reject );
     25 
     26 		// Other thenables
     27 		} else if ( value && isFunction( ( method = value.then ) ) ) {
     28 			method.call( value, resolve, reject );
     29 
     30 		// Other non-thenables
     31 		} else {
     32 
     33 			// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
     34 			// * false: [ value ].slice( 0 ) => resolve( value )
     35 			// * true: [ value ].slice( 1 ) => resolve()
     36 			resolve.apply( undefined, [ value ].slice( noValue ) );
     37 		}
     38 
     39 	// For Promises/A+, convert exceptions into rejections
     40 	// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
     41 	// Deferred#then to conditionally suppress rejection.
     42 	} catch ( value ) {
     43 
     44 		// Support: Android 4.0 only
     45 		// Strict mode functions invoked without .call/.apply get global-object context
     46 		reject.apply( undefined, [ value ] );
     47 	}
     48 }
     49 
     50 jQuery.extend( {
     51 
     52 	Deferred: function( func ) {
     53 		var tuples = [
     54 
     55 				// action, add listener, callbacks,
     56 				// ... .then handlers, argument index, [final state]
     57 				[ "notify", "progress", jQuery.Callbacks( "memory" ),
     58 					jQuery.Callbacks( "memory" ), 2 ],
     59 				[ "resolve", "done", jQuery.Callbacks( "once memory" ),
     60 					jQuery.Callbacks( "once memory" ), 0, "resolved" ],
     61 				[ "reject", "fail", jQuery.Callbacks( "once memory" ),
     62 					jQuery.Callbacks( "once memory" ), 1, "rejected" ]
     63 			],
     64 			state = "pending",
     65 			promise = {
     66 				state: function() {
     67 					return state;
     68 				},
     69 				always: function() {
     70 					deferred.done( arguments ).fail( arguments );
     71 					return this;
     72 				},
     73 				"catch": function( fn ) {
     74 					return promise.then( null, fn );
     75 				},
     76 
     77 				// Keep pipe for back-compat
     78 				pipe: function( /* fnDone, fnFail, fnProgress */ ) {
     79 					var fns = arguments;
     80 
     81 					return jQuery.Deferred( function( newDefer ) {
     82 						jQuery.each( tuples, function( _i, tuple ) {
     83 
     84 							// Map tuples (progress, done, fail) to arguments (done, fail, progress)
     85 							var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
     86 
     87 							// deferred.progress(function() { bind to newDefer or newDefer.notify })
     88 							// deferred.done(function() { bind to newDefer or newDefer.resolve })
     89 							// deferred.fail(function() { bind to newDefer or newDefer.reject })
     90 							deferred[ tuple[ 1 ] ]( function() {
     91 								var returned = fn && fn.apply( this, arguments );
     92 								if ( returned && isFunction( returned.promise ) ) {
     93 									returned.promise()
     94 										.progress( newDefer.notify )
     95 										.done( newDefer.resolve )
     96 										.fail( newDefer.reject );
     97 								} else {
     98 									newDefer[ tuple[ 0 ] + "With" ](
     99 										this,
    100 										fn ? [ returned ] : arguments
    101 									);
    102 								}
    103 							} );
    104 						} );
    105 						fns = null;
    106 					} ).promise();
    107 				},
    108 				then: function( onFulfilled, onRejected, onProgress ) {
    109 					var maxDepth = 0;
    110 					function resolve( depth, deferred, handler, special ) {
    111 						return function() {
    112 							var that = this,
    113 								args = arguments,
    114 								mightThrow = function() {
    115 									var returned, then;
    116 
    117 									// Support: Promises/A+ section 2.3.3.3.3
    118 									// https://promisesaplus.com/#point-59
    119 									// Ignore double-resolution attempts
    120 									if ( depth < maxDepth ) {
    121 										return;
    122 									}
    123 
    124 									returned = handler.apply( that, args );
    125 
    126 									// Support: Promises/A+ section 2.3.1
    127 									// https://promisesaplus.com/#point-48
    128 									if ( returned === deferred.promise() ) {
    129 										throw new TypeError( "Thenable self-resolution" );
    130 									}
    131 
    132 									// Support: Promises/A+ sections 2.3.3.1, 3.5
    133 									// https://promisesaplus.com/#point-54
    134 									// https://promisesaplus.com/#point-75
    135 									// Retrieve `then` only once
    136 									then = returned &&
    137 
    138 										// Support: Promises/A+ section 2.3.4
    139 										// https://promisesaplus.com/#point-64
    140 										// Only check objects and functions for thenability
    141 										( typeof returned === "object" ||
    142 											typeof returned === "function" ) &&
    143 										returned.then;
    144 
    145 									// Handle a returned thenable
    146 									if ( isFunction( then ) ) {
    147 
    148 										// Special processors (notify) just wait for resolution
    149 										if ( special ) {
    150 											then.call(
    151 												returned,
    152 												resolve( maxDepth, deferred, Identity, special ),
    153 												resolve( maxDepth, deferred, Thrower, special )
    154 											);
    155 
    156 										// Normal processors (resolve) also hook into progress
    157 										} else {
    158 
    159 											// ...and disregard older resolution values
    160 											maxDepth++;
    161 
    162 											then.call(
    163 												returned,
    164 												resolve( maxDepth, deferred, Identity, special ),
    165 												resolve( maxDepth, deferred, Thrower, special ),
    166 												resolve( maxDepth, deferred, Identity,
    167 													deferred.notifyWith )
    168 											);
    169 										}
    170 
    171 									// Handle all other returned values
    172 									} else {
    173 
    174 										// Only substitute handlers pass on context
    175 										// and multiple values (non-spec behavior)
    176 										if ( handler !== Identity ) {
    177 											that = undefined;
    178 											args = [ returned ];
    179 										}
    180 
    181 										// Process the value(s)
    182 										// Default process is resolve
    183 										( special || deferred.resolveWith )( that, args );
    184 									}
    185 								},
    186 
    187 								// Only normal processors (resolve) catch and reject exceptions
    188 								process = special ?
    189 									mightThrow :
    190 									function() {
    191 										try {
    192 											mightThrow();
    193 										} catch ( e ) {
    194 
    195 											if ( jQuery.Deferred.exceptionHook ) {
    196 												jQuery.Deferred.exceptionHook( e,
    197 													process.error );
    198 											}
    199 
    200 											// Support: Promises/A+ section 2.3.3.3.4.1
    201 											// https://promisesaplus.com/#point-61
    202 											// Ignore post-resolution exceptions
    203 											if ( depth + 1 >= maxDepth ) {
    204 
    205 												// Only substitute handlers pass on context
    206 												// and multiple values (non-spec behavior)
    207 												if ( handler !== Thrower ) {
    208 													that = undefined;
    209 													args = [ e ];
    210 												}
    211 
    212 												deferred.rejectWith( that, args );
    213 											}
    214 										}
    215 									};
    216 
    217 							// Support: Promises/A+ section 2.3.3.3.1
    218 							// https://promisesaplus.com/#point-57
    219 							// Re-resolve promises immediately to dodge false rejection from
    220 							// subsequent errors
    221 							if ( depth ) {
    222 								process();
    223 							} else {
    224 
    225 								// Call an optional hook to record the error, in case of exception
    226 								// since it's otherwise lost when execution goes async
    227 								if ( jQuery.Deferred.getErrorHook ) {
    228 									process.error = jQuery.Deferred.getErrorHook();
    229 
    230 								// The deprecated alias of the above. While the name suggests
    231 								// returning the stack, not an error instance, jQuery just passes
    232 								// it directly to `console.warn` so both will work; an instance
    233 								// just better cooperates with source maps.
    234 								} else if ( jQuery.Deferred.getStackHook ) {
    235 									process.error = jQuery.Deferred.getStackHook();
    236 								}
    237 								window.setTimeout( process );
    238 							}
    239 						};
    240 					}
    241 
    242 					return jQuery.Deferred( function( newDefer ) {
    243 
    244 						// progress_handlers.add( ... )
    245 						tuples[ 0 ][ 3 ].add(
    246 							resolve(
    247 								0,
    248 								newDefer,
    249 								isFunction( onProgress ) ?
    250 									onProgress :
    251 									Identity,
    252 								newDefer.notifyWith
    253 							)
    254 						);
    255 
    256 						// fulfilled_handlers.add( ... )
    257 						tuples[ 1 ][ 3 ].add(
    258 							resolve(
    259 								0,
    260 								newDefer,
    261 								isFunction( onFulfilled ) ?
    262 									onFulfilled :
    263 									Identity
    264 							)
    265 						);
    266 
    267 						// rejected_handlers.add( ... )
    268 						tuples[ 2 ][ 3 ].add(
    269 							resolve(
    270 								0,
    271 								newDefer,
    272 								isFunction( onRejected ) ?
    273 									onRejected :
    274 									Thrower
    275 							)
    276 						);
    277 					} ).promise();
    278 				},
    279 
    280 				// Get a promise for this deferred
    281 				// If obj is provided, the promise aspect is added to the object
    282 				promise: function( obj ) {
    283 					return obj != null ? jQuery.extend( obj, promise ) : promise;
    284 				}
    285 			},
    286 			deferred = {};
    287 
    288 		// Add list-specific methods
    289 		jQuery.each( tuples, function( i, tuple ) {
    290 			var list = tuple[ 2 ],
    291 				stateString = tuple[ 5 ];
    292 
    293 			// promise.progress = list.add
    294 			// promise.done = list.add
    295 			// promise.fail = list.add
    296 			promise[ tuple[ 1 ] ] = list.add;
    297 
    298 			// Handle state
    299 			if ( stateString ) {
    300 				list.add(
    301 					function() {
    302 
    303 						// state = "resolved" (i.e., fulfilled)
    304 						// state = "rejected"
    305 						state = stateString;
    306 					},
    307 
    308 					// rejected_callbacks.disable
    309 					// fulfilled_callbacks.disable
    310 					tuples[ 3 - i ][ 2 ].disable,
    311 
    312 					// rejected_handlers.disable
    313 					// fulfilled_handlers.disable
    314 					tuples[ 3 - i ][ 3 ].disable,
    315 
    316 					// progress_callbacks.lock
    317 					tuples[ 0 ][ 2 ].lock,
    318 
    319 					// progress_handlers.lock
    320 					tuples[ 0 ][ 3 ].lock
    321 				);
    322 			}
    323 
    324 			// progress_handlers.fire
    325 			// fulfilled_handlers.fire
    326 			// rejected_handlers.fire
    327 			list.add( tuple[ 3 ].fire );
    328 
    329 			// deferred.notify = function() { deferred.notifyWith(...) }
    330 			// deferred.resolve = function() { deferred.resolveWith(...) }
    331 			// deferred.reject = function() { deferred.rejectWith(...) }
    332 			deferred[ tuple[ 0 ] ] = function() {
    333 				deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
    334 				return this;
    335 			};
    336 
    337 			// deferred.notifyWith = list.fireWith
    338 			// deferred.resolveWith = list.fireWith
    339 			// deferred.rejectWith = list.fireWith
    340 			deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
    341 		} );
    342 
    343 		// Make the deferred a promise
    344 		promise.promise( deferred );
    345 
    346 		// Call given func if any
    347 		if ( func ) {
    348 			func.call( deferred, deferred );
    349 		}
    350 
    351 		// All done!
    352 		return deferred;
    353 	},
    354 
    355 	// Deferred helper
    356 	when: function( singleValue ) {
    357 		var
    358 
    359 			// count of uncompleted subordinates
    360 			remaining = arguments.length,
    361 
    362 			// count of unprocessed arguments
    363 			i = remaining,
    364 
    365 			// subordinate fulfillment data
    366 			resolveContexts = Array( i ),
    367 			resolveValues = slice.call( arguments ),
    368 
    369 			// the primary Deferred
    370 			primary = jQuery.Deferred(),
    371 
    372 			// subordinate callback factory
    373 			updateFunc = function( i ) {
    374 				return function( value ) {
    375 					resolveContexts[ i ] = this;
    376 					resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
    377 					if ( !( --remaining ) ) {
    378 						primary.resolveWith( resolveContexts, resolveValues );
    379 					}
    380 				};
    381 			};
    382 
    383 		// Single- and empty arguments are adopted like Promise.resolve
    384 		if ( remaining <= 1 ) {
    385 			adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject,
    386 				!remaining );
    387 
    388 			// Use .then() to unwrap secondary thenables (cf. gh-3000)
    389 			if ( primary.state() === "pending" ||
    390 				isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
    391 
    392 				return primary.then();
    393 			}
    394 		}
    395 
    396 		// Multiple arguments are aggregated like Promise.all array elements
    397 		while ( i-- ) {
    398 			adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject );
    399 		}
    400 
    401 		return primary.promise();
    402 	}
    403 } );
    404 
    405 return jQuery;
    406 } );