216
216
*
217
217
* @returns {Promise } The newly created promise.
218
218
*/
219
+ /**
220
+ * @ngdoc provider
221
+ * @name $qProvider
222
+ *
223
+ * @description
224
+ */
219
225
function $QProvider ( ) {
220
-
226
+ var errorOnUnhandledRejections = true ;
221
227
this . $get = [ '$rootScope' , '$exceptionHandler' , function ( $rootScope , $exceptionHandler ) {
222
228
return qFactory ( function ( callback ) {
223
229
$rootScope . $evalAsync ( callback ) ;
224
- } , $exceptionHandler ) ;
230
+ } , $exceptionHandler , errorOnUnhandledRejections ) ;
225
231
} ] ;
232
+
233
+ /**
234
+ * @ngdoc method
235
+ * @name $qProvider#errorOnUnhandledRejections
236
+ * @kind function
237
+ *
238
+ * @description
239
+ * Retrieves or overrides whether to generate an error when a rejected promise is not handled.
240
+ *
241
+ * @param {boolean= } value Whether to generate an error when a rejected promise is not handled.
242
+ * @returns {boolean|ng.$qProvider } Current value when called without a new value or self for
243
+ * chaining otherwise.
244
+ */
245
+ this . errorOnUnhandledRejections = function ( value ) {
246
+ if ( isDefined ( value ) ) {
247
+ errorOnUnhandledRejections = value ;
248
+ return this ;
249
+ } else {
250
+ return errorOnUnhandledRejections ;
251
+ }
252
+ } ;
226
253
}
227
254
228
255
function $$QProvider ( ) {
256
+ var errorOnUnhandledRejections = true ;
229
257
this . $get = [ '$browser' , '$exceptionHandler' , function ( $browser , $exceptionHandler ) {
230
258
return qFactory ( function ( callback ) {
231
259
$browser . defer ( callback ) ;
232
- } , $exceptionHandler ) ;
260
+ } , $exceptionHandler , errorOnUnhandledRejections ) ;
233
261
} ] ;
262
+
263
+ this . errorOnUnhandledRejections = function ( value ) {
264
+ if ( isDefined ( value ) ) {
265
+ errorOnUnhandledRejections = value ;
266
+ return this ;
267
+ } else {
268
+ return errorOnUnhandledRejections ;
269
+ }
270
+ } ;
234
271
}
235
272
236
273
/**
@@ -239,10 +276,14 @@ function $$QProvider() {
239
276
* @param {function(function) } nextTick Function for executing functions in the next turn.
240
277
* @param {function(...*) } exceptionHandler Function into which unexpected exceptions are passed for
241
278
* debugging purposes.
279
+ @ param {=boolean} errorOnUnhandledRejections Whether an error should be generated on unhandled
280
+ * promises rejections.
242
281
* @returns {object } Promise manager.
243
282
*/
244
- function qFactory ( nextTick , exceptionHandler ) {
283
+ function qFactory ( nextTick , exceptionHandler , errorOnUnhandledRejections ) {
245
284
var $qMinErr = minErr ( '$q' , TypeError ) ;
285
+ var queueSize = 0 ;
286
+ var checkQueue = [ ] ;
246
287
247
288
/**
248
289
* @ngdoc method
@@ -307,28 +348,62 @@ function qFactory(nextTick, exceptionHandler) {
307
348
pending = state . pending ;
308
349
state . processScheduled = false ;
309
350
state . pending = undefined ;
310
- for ( var i = 0 , ii = pending . length ; i < ii ; ++ i ) {
311
- deferred = pending [ i ] [ 0 ] ;
312
- fn = pending [ i ] [ state . status ] ;
313
- try {
314
- if ( isFunction ( fn ) ) {
315
- deferred . resolve ( fn ( state . value ) ) ;
316
- } else if ( state . status === 1 ) {
317
- deferred . resolve ( state . value ) ;
318
- } else {
319
- deferred . reject ( state . value ) ;
351
+ try {
352
+ for ( var i = 0 , ii = pending . length ; i < ii ; ++ i ) {
353
+ state . pur = true ;
354
+ deferred = pending [ i ] [ 0 ] ;
355
+ fn = pending [ i ] [ state . status ] ;
356
+ try {
357
+ if ( isFunction ( fn ) ) {
358
+ deferred . resolve ( fn ( state . value ) ) ;
359
+ } else if ( state . status === 1 ) {
360
+ deferred . resolve ( state . value ) ;
361
+ } else {
362
+ deferred . reject ( state . value ) ;
363
+ }
364
+ } catch ( e ) {
365
+ deferred . reject ( e ) ;
366
+ exceptionHandler ( e ) ;
320
367
}
321
- } catch ( e ) {
322
- deferred . reject ( e ) ;
323
- exceptionHandler ( e ) ;
368
+ }
369
+ } finally {
370
+ -- queueSize ;
371
+ if ( errorOnUnhandledRejections && queueSize === 0 ) {
372
+ nextTick ( processChecksFn ( ) ) ;
373
+ }
374
+ }
375
+ }
376
+
377
+ function processChecks ( ) {
378
+ while ( ! queueSize && checkQueue . length ) {
379
+ var toCheck = checkQueue . shift ( ) ;
380
+ if ( ! toCheck . pur ) {
381
+ toCheck . pur = true ;
382
+ var errorMessage = 'Possibly unhandled rejection: ' + toDebugString ( toCheck . value ) ;
383
+ exceptionHandler ( errorMessage ) ;
324
384
}
325
385
}
326
386
}
327
387
388
+ function processChecksFn ( ) {
389
+ return function ( ) { processChecks ( ) ; } ;
390
+ }
391
+
392
+ function processQueueFn ( state ) {
393
+ return function ( ) { processQueue ( state ) ; } ;
394
+ }
395
+
328
396
function scheduleProcessQueue ( state ) {
397
+ if ( errorOnUnhandledRejections && ! state . pending && state . status === 2 && ! state . pur ) {
398
+ if ( queueSize === 0 && checkQueue . length === 0 ) {
399
+ nextTick ( processChecksFn ( ) ) ;
400
+ }
401
+ checkQueue . push ( state ) ;
402
+ }
329
403
if ( state . processScheduled || ! state . pending ) return ;
330
404
state . processScheduled = true ;
331
- nextTick ( function ( ) { processQueue ( state ) ; } ) ;
405
+ ++ queueSize ;
406
+ nextTick ( processQueueFn ( state ) ) ;
332
407
}
333
408
334
409
function Deferred ( ) {
0 commit comments