@@ -229,18 +229,29 @@ function $$QProvider() {
229
229
/**
230
230
* Constructs a promise manager.
231
231
*
232
- * @param {function(Function ) } nextTick Function for executing functions in the next turn.
232
+ * @param {function(function ) } nextTick Function for executing functions in the next turn.
233
233
* @param {function(...*) } exceptionHandler Function into which unexpected exceptions are passed for
234
234
* debugging purposes.
235
235
* @returns {object } Promise manager.
236
236
*/
237
237
function qFactory ( nextTick , exceptionHandler ) {
238
+ function callOnce ( self , resolveFn , rejectFn ) {
239
+ var called = false ;
240
+ function wrap ( fn ) {
241
+ return function ( value ) {
242
+ if ( called ) return ;
243
+ called = true ;
244
+ fn . call ( self , value ) ;
245
+ } ;
246
+ }
247
+
248
+ return [ wrap ( resolveFn ) , wrap ( rejectFn ) ] ;
249
+ }
238
250
239
251
/**
240
- * @ngdoc method
241
- * @name $q#defer
242
- * @kind function
243
- *
252
+ * @ngdoc
253
+ * @name ng.$q#defer
254
+ * @methodOf ng.$q
244
255
* @description
245
256
* Creates a `Deferred` object which represents a task which will finish in the future.
246
257
*
@@ -250,58 +261,31 @@ function qFactory(nextTick, exceptionHandler) {
250
261
return new Deferred ( ) ;
251
262
} ;
252
263
253
- function Promise ( ) {
254
- this . $$pending = [ ] ;
264
+ function Promise ( ) {
265
+ this . $$state = { status : 0 } ;
255
266
}
256
267
257
268
Promise . prototype = {
258
- then : function ( callback , errback , progressback ) {
269
+ then : function ( onFulfilled , onRejected , progressBack ) {
259
270
var result = new Deferred ( ) ;
260
271
261
- var wrappedCallback = function ( value ) {
262
- try {
263
- result . resolve ( ( isFunction ( callback ) ? callback : defaultCallback ) ( value ) ) ;
264
- } catch ( e ) {
265
- result . reject ( e ) ;
266
- exceptionHandler ( e ) ;
267
- }
268
- } ;
269
-
270
- var wrappedErrback = function ( reason ) {
271
- try {
272
- result . resolve ( ( isFunction ( errback ) ? errback : defaultErrback ) ( reason ) ) ;
273
- } catch ( e ) {
274
- result . reject ( e ) ;
275
- exceptionHandler ( e ) ;
276
- }
277
- } ;
278
-
279
- var wrappedProgressback = function ( progress ) {
280
- try {
281
- result . notify ( ( isFunction ( progressback ) ? progressback : defaultCallback ) ( progress ) ) ;
282
- } catch ( e ) {
283
- exceptionHandler ( e ) ;
284
- }
285
- } ;
286
-
287
- if ( this . $$pending ) {
288
- this . $$pending . push ( [ wrappedCallback , wrappedErrback , wrappedProgressback ] ) ;
289
- } else {
290
- this . $$value . then ( wrappedCallback , wrappedErrback , wrappedProgressback ) ;
291
- }
272
+ this . $$state . pending = this . $$state . pending || [ ] ;
273
+ this . $$state . pending . push ( [ result , onFulfilled , onRejected , progressBack ] ) ;
274
+ if ( this . $$state . status > 0 ) scheduleProcessQueue ( this . $$state ) ;
292
275
293
276
return result . promise ;
294
277
} ,
295
278
296
279
"catch" : function ( callback ) {
297
280
return this . then ( null , callback ) ;
298
281
} ,
299
- "finally" : function ( callback ) {
282
+
283
+ "finally" : function ( callback , progressBack ) {
300
284
return this . then ( function ( value ) {
301
285
return handleCallback ( value , true , callback ) ;
302
286
} , function ( error ) {
303
287
return handleCallback ( error , false , callback ) ;
304
- } ) ;
288
+ } , progressBack ) ;
305
289
}
306
290
} ;
307
291
@@ -312,7 +296,37 @@ function qFactory(nextTick, exceptionHandler) {
312
296
} ;
313
297
}
314
298
315
- function Deferred ( ) {
299
+ function processQueue ( state ) {
300
+ var fn , promise , pending ;
301
+
302
+ pending = state . pending ;
303
+ state . processScheduled = false ;
304
+ state . pending = undefined ;
305
+ for ( var i = 0 , ii = pending . length ; i < ii ; ++ i ) {
306
+ promise = pending [ i ] [ 0 ] ;
307
+ fn = pending [ i ] [ state . status ] ;
308
+ try {
309
+ if ( isFunction ( fn ) ) {
310
+ promise . resolve ( fn ( state . value ) ) ;
311
+ } else if ( state . status === 1 ) {
312
+ promise . resolve ( state . value ) ;
313
+ } else {
314
+ promise . reject ( state . value ) ;
315
+ }
316
+ } catch ( e ) {
317
+ promise . reject ( e ) ;
318
+ exceptionHandler ( e ) ;
319
+ }
320
+ }
321
+ }
322
+
323
+ function scheduleProcessQueue ( state ) {
324
+ if ( state . processScheduled || ! state . pending ) return ;
325
+ state . processScheduled = true ;
326
+ nextTick ( function ( ) { processQueue ( state ) ; } ) ;
327
+ }
328
+
329
+ function Deferred ( ) {
316
330
this . promise = new Promise ( ) ;
317
331
//Necessary to support unbound execution :/
318
332
this . resolve = simpleBind ( this , this . resolve ) ;
@@ -322,61 +336,66 @@ function qFactory(nextTick, exceptionHandler) {
322
336
323
337
Deferred . prototype = {
324
338
resolve : function ( val ) {
325
- if ( this . promise . $$pending ) {
326
- var callbacks = this . promise . $$pending ;
327
- this . promise . $$pending = undefined ;
328
- this . promise . $$value = ref ( val ) ;
329
-
330
- if ( callbacks . length ) {
331
- nextTick ( simpleBind ( this , function ( ) {
332
- var callback ;
333
- for ( var i = 0 , ii = callbacks . length ; i < ii ; i ++ ) {
334
- callback = callbacks [ i ] ;
335
- this . promise . $$value . then ( callback [ 0 ] , callback [ 1 ] , callback [ 2 ] ) ;
336
- }
337
- } ) ) ;
339
+ if ( this . promise . $$state . status ) return ;
340
+ if ( val === this . promise ) throw new TypeError ( 'Cycle detected' ) ;
341
+ this . $$resolve ( val ) ;
342
+ } ,
343
+
344
+ $$resolve : function ( val ) {
345
+ var then , fns ;
346
+
347
+ fns = callOnce ( this , this . $$resolve , this . $$reject ) ;
348
+ try {
349
+ if ( ( isObject ( val ) || isFunction ( val ) ) ) then = val && val . then ;
350
+ if ( isFunction ( then ) ) {
351
+ this . promise . $$state . status = - 1 ;
352
+ then . call ( val , fns [ 0 ] , fns [ 1 ] , this . notify ) ;
353
+ } else {
354
+ this . promise . $$state . value = val ;
355
+ this . promise . $$state . status = 1 ;
356
+ scheduleProcessQueue ( this . promise . $$state ) ;
338
357
}
358
+ } catch ( e ) {
359
+ fns [ 1 ] ( e ) ;
360
+ exceptionHandler ( e ) ;
339
361
}
340
362
} ,
363
+
341
364
reject : function ( reason ) {
342
- this . resolve ( createInternalRejectedPromise ( reason ) ) ;
365
+ if ( this . promise . $$state . status ) return ;
366
+ this . $$reject ( reason ) ;
367
+ } ,
368
+
369
+ $$reject : function ( reason ) {
370
+ this . promise . $$state . value = reason ;
371
+ this . promise . $$state . status = 2 ;
372
+ scheduleProcessQueue ( this . promise . $$state ) ;
343
373
} ,
374
+
344
375
notify : function ( progress ) {
345
- if ( this . promise . $$pending ) {
346
- var callbacks = this . promise . $$pending ;
347
-
348
- if ( this . promise . $$pending . length ) {
349
- nextTick ( function ( ) {
350
- var callback ;
351
- for ( var i = 0 , ii = callbacks . length ; i < ii ; i ++ ) {
352
- callback = callbacks [ i ] ;
353
- callback [ 2 ] ( progress ) ;
354
- }
355
- } ) ;
356
- }
357
- }
358
- }
359
- } ;
376
+ var callbacks = this . promise . $$state . pending ;
360
377
361
- var ref = function ( value ) {
362
- if ( isPromiseLike ( value ) ) return value ;
363
- return {
364
- then : function ( callback ) {
365
- var result = new Deferred ( ) ;
378
+ if ( ( this . promise . $$state . status <= 0 ) && callbacks && callbacks . length ) {
366
379
nextTick ( function ( ) {
367
- result . resolve ( callback ( value ) ) ;
380
+ var callback , result ;
381
+ for ( var i = 0 , ii = callbacks . length ; i < ii ; i ++ ) {
382
+ result = callbacks [ i ] [ 0 ] ;
383
+ callback = callbacks [ i ] [ 3 ] ;
384
+ try {
385
+ result . notify ( isFunction ( callback ) ? callback ( progress ) : progress ) ;
386
+ } catch ( e ) {
387
+ exceptionHandler ( e ) ;
388
+ }
389
+ }
368
390
} ) ;
369
- return result . promise ;
370
391
}
371
- } ;
392
+ }
372
393
} ;
373
394
374
-
375
395
/**
376
- * @ngdoc method
377
- * @name $q#reject
378
- * @kind function
379
- *
396
+ * @ngdoc
397
+ * @name ng.$q#reject
398
+ * @methodOf ng.$q
380
399
* @description
381
400
* Creates a promise that is resolved as rejected with the specified `reason`. This api should be
382
401
* used to forward rejection in a chain of promises. If you are dealing with the last promise in
@@ -427,7 +446,7 @@ function qFactory(nextTick, exceptionHandler) {
427
446
var handleCallback = function handleCallback ( value , isResolved , callback ) {
428
447
var callbackOutput = null ;
429
448
try {
430
- callbackOutput = ( callback || defaultCallback ) ( ) ;
449
+ if ( isFunction ( callback ) ) callbackOutput = callback ( ) ;
431
450
} catch ( e ) {
432
451
return makePromise ( e , false ) ;
433
452
}
@@ -442,29 +461,10 @@ function qFactory(nextTick, exceptionHandler) {
442
461
}
443
462
} ;
444
463
445
- var createInternalRejectedPromise = function ( reason ) {
446
- return {
447
- then : function ( callback , errback ) {
448
- var result = new Deferred ( ) ;
449
- nextTick ( function ( ) {
450
- try {
451
- result . resolve ( ( isFunction ( errback ) ? errback : defaultErrback ) ( reason ) ) ;
452
- } catch ( e ) {
453
- result . reject ( e ) ;
454
- exceptionHandler ( e ) ;
455
- }
456
- } ) ;
457
- return result . promise ;
458
- }
459
- } ;
460
- } ;
461
-
462
-
463
464
/**
464
- * @ngdoc method
465
- * @name $q#when
466
- * @kind function
467
- *
465
+ * @ngdoc
466
+ * @name ng.$q#when
467
+ * @methodOf ng.$q
468
468
* @description
469
469
* Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
470
470
* This is useful when you are dealing with an object that might or might not be a promise, or if
@@ -473,70 +473,18 @@ function qFactory(nextTick, exceptionHandler) {
473
473
* @param {* } value Value or a promise
474
474
* @returns {Promise } Returns a promise of the passed value or promise
475
475
*/
476
- var when = function ( value , callback , errback , progressback ) {
477
- var result = new Deferred ( ) ,
478
- done ;
479
476
480
- var wrappedCallback = function ( value ) {
481
- try {
482
- return ( isFunction ( callback ) ? callback : defaultCallback ) ( value ) ;
483
- } catch ( e ) {
484
- exceptionHandler ( e ) ;
485
- return reject ( e ) ;
486
- }
487
- } ;
488
477
489
- var wrappedErrback = function ( reason ) {
490
- try {
491
- return ( isFunction ( errback ) ? errback : defaultErrback ) ( reason ) ;
492
- } catch ( e ) {
493
- exceptionHandler ( e ) ;
494
- return reject ( e ) ;
495
- }
496
- } ;
497
-
498
- var wrappedProgressback = function ( progress ) {
499
- try {
500
- return ( isFunction ( progressback ) ? progressback : defaultCallback ) ( progress ) ;
501
- } catch ( e ) {
502
- exceptionHandler ( e ) ;
503
- }
504
- } ;
505
-
506
- nextTick ( function ( ) {
507
- ref ( value ) . then ( function ( value ) {
508
- if ( done ) return ;
509
- done = true ;
510
- result . resolve ( ref ( value ) . then ( wrappedCallback , wrappedErrback , wrappedProgressback ) ) ;
511
- } , function ( reason ) {
512
- if ( done ) return ;
513
- done = true ;
514
- result . resolve ( wrappedErrback ( reason ) ) ;
515
- } , function ( progress ) {
516
- if ( done ) return ;
517
- result . notify ( wrappedProgressback ( progress ) ) ;
518
- } ) ;
519
- } ) ;
520
-
521
- return result . promise ;
478
+ var when = function ( value , callback , errback , progressBack ) {
479
+ var result = new Deferred ( ) ;
480
+ result . resolve ( value ) ;
481
+ return result . promise . then ( callback , errback , progressBack ) ;
522
482
} ;
523
483
524
-
525
- function defaultCallback ( value ) {
526
- return value ;
527
- }
528
-
529
-
530
- function defaultErrback ( reason ) {
531
- return reject ( reason ) ;
532
- }
533
-
534
-
535
484
/**
536
- * @ngdoc method
537
- * @name $q#all
538
- * @kind function
539
- *
485
+ * @ngdoc
486
+ * @name ng.$q#all
487
+ * @methodOf ng.$q
540
488
* @description
541
489
* Combines multiple promises into a single promise that is resolved when all of the input
542
490
* promises are resolved.
@@ -547,14 +495,15 @@ function qFactory(nextTick, exceptionHandler) {
547
495
* If any of the promises is resolved with a rejection, this resulting promise will be rejected
548
496
* with the same rejection value.
549
497
*/
498
+
550
499
function all ( promises ) {
551
500
var deferred = new Deferred ( ) ,
552
501
counter = 0 ,
553
502
results = isArray ( promises ) ? [ ] : { } ;
554
503
555
504
forEach ( promises , function ( promise , key ) {
556
505
counter ++ ;
557
- ref ( promise ) . then ( function ( value ) {
506
+ when ( promise ) . then ( function ( value ) {
558
507
if ( results . hasOwnProperty ( key ) ) return ;
559
508
results [ key ] = value ;
560
509
if ( ! ( -- counter ) ) deferred . resolve ( results ) ;
0 commit comments