Mercurial > nebulaweb3
comparison default/node_modules/jquery/src/deferred.js @ 0:1d038bc9b3d2 default tip
Up:default
author | Liny <dev@neowd.com> |
---|---|
date | Sat, 31 May 2025 09:21:51 +0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1d038bc9b3d2 |
---|---|
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.stackTrace ); | |
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 stack, in case of exception | |
226 // since it's otherwise lost when execution goes async | |
227 if ( jQuery.Deferred.getStackHook ) { | |
228 process.stackTrace = jQuery.Deferred.getStackHook(); | |
229 } | |
230 window.setTimeout( process ); | |
231 } | |
232 }; | |
233 } | |
234 | |
235 return jQuery.Deferred( function( newDefer ) { | |
236 | |
237 // progress_handlers.add( ... ) | |
238 tuples[ 0 ][ 3 ].add( | |
239 resolve( | |
240 0, | |
241 newDefer, | |
242 isFunction( onProgress ) ? | |
243 onProgress : | |
244 Identity, | |
245 newDefer.notifyWith | |
246 ) | |
247 ); | |
248 | |
249 // fulfilled_handlers.add( ... ) | |
250 tuples[ 1 ][ 3 ].add( | |
251 resolve( | |
252 0, | |
253 newDefer, | |
254 isFunction( onFulfilled ) ? | |
255 onFulfilled : | |
256 Identity | |
257 ) | |
258 ); | |
259 | |
260 // rejected_handlers.add( ... ) | |
261 tuples[ 2 ][ 3 ].add( | |
262 resolve( | |
263 0, | |
264 newDefer, | |
265 isFunction( onRejected ) ? | |
266 onRejected : | |
267 Thrower | |
268 ) | |
269 ); | |
270 } ).promise(); | |
271 }, | |
272 | |
273 // Get a promise for this deferred | |
274 // If obj is provided, the promise aspect is added to the object | |
275 promise: function( obj ) { | |
276 return obj != null ? jQuery.extend( obj, promise ) : promise; | |
277 } | |
278 }, | |
279 deferred = {}; | |
280 | |
281 // Add list-specific methods | |
282 jQuery.each( tuples, function( i, tuple ) { | |
283 var list = tuple[ 2 ], | |
284 stateString = tuple[ 5 ]; | |
285 | |
286 // promise.progress = list.add | |
287 // promise.done = list.add | |
288 // promise.fail = list.add | |
289 promise[ tuple[ 1 ] ] = list.add; | |
290 | |
291 // Handle state | |
292 if ( stateString ) { | |
293 list.add( | |
294 function() { | |
295 | |
296 // state = "resolved" (i.e., fulfilled) | |
297 // state = "rejected" | |
298 state = stateString; | |
299 }, | |
300 | |
301 // rejected_callbacks.disable | |
302 // fulfilled_callbacks.disable | |
303 tuples[ 3 - i ][ 2 ].disable, | |
304 | |
305 // rejected_handlers.disable | |
306 // fulfilled_handlers.disable | |
307 tuples[ 3 - i ][ 3 ].disable, | |
308 | |
309 // progress_callbacks.lock | |
310 tuples[ 0 ][ 2 ].lock, | |
311 | |
312 // progress_handlers.lock | |
313 tuples[ 0 ][ 3 ].lock | |
314 ); | |
315 } | |
316 | |
317 // progress_handlers.fire | |
318 // fulfilled_handlers.fire | |
319 // rejected_handlers.fire | |
320 list.add( tuple[ 3 ].fire ); | |
321 | |
322 // deferred.notify = function() { deferred.notifyWith(...) } | |
323 // deferred.resolve = function() { deferred.resolveWith(...) } | |
324 // deferred.reject = function() { deferred.rejectWith(...) } | |
325 deferred[ tuple[ 0 ] ] = function() { | |
326 deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); | |
327 return this; | |
328 }; | |
329 | |
330 // deferred.notifyWith = list.fireWith | |
331 // deferred.resolveWith = list.fireWith | |
332 // deferred.rejectWith = list.fireWith | |
333 deferred[ tuple[ 0 ] + "With" ] = list.fireWith; | |
334 } ); | |
335 | |
336 // Make the deferred a promise | |
337 promise.promise( deferred ); | |
338 | |
339 // Call given func if any | |
340 if ( func ) { | |
341 func.call( deferred, deferred ); | |
342 } | |
343 | |
344 // All done! | |
345 return deferred; | |
346 }, | |
347 | |
348 // Deferred helper | |
349 when: function( singleValue ) { | |
350 var | |
351 | |
352 // count of uncompleted subordinates | |
353 remaining = arguments.length, | |
354 | |
355 // count of unprocessed arguments | |
356 i = remaining, | |
357 | |
358 // subordinate fulfillment data | |
359 resolveContexts = Array( i ), | |
360 resolveValues = slice.call( arguments ), | |
361 | |
362 // the master Deferred | |
363 master = jQuery.Deferred(), | |
364 | |
365 // subordinate callback factory | |
366 updateFunc = function( i ) { | |
367 return function( value ) { | |
368 resolveContexts[ i ] = this; | |
369 resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; | |
370 if ( !( --remaining ) ) { | |
371 master.resolveWith( resolveContexts, resolveValues ); | |
372 } | |
373 }; | |
374 }; | |
375 | |
376 // Single- and empty arguments are adopted like Promise.resolve | |
377 if ( remaining <= 1 ) { | |
378 adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, | |
379 !remaining ); | |
380 | |
381 // Use .then() to unwrap secondary thenables (cf. gh-3000) | |
382 if ( master.state() === "pending" || | |
383 isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { | |
384 | |
385 return master.then(); | |
386 } | |
387 } | |
388 | |
389 // Multiple arguments are aggregated like Promise.all array elements | |
390 while ( i-- ) { | |
391 adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); | |
392 } | |
393 | |
394 return master.promise(); | |
395 } | |
396 } ); | |
397 | |
398 return jQuery; | |
399 } ); |