|
1 | 1 | 'use strict';
|
2 | 2 |
|
3 | 3 | /**
|
4 |
| - * Constructs a promise manager. |
| 4 | + * @ngdoc service |
| 5 | + * @name angular.module.ng.$q |
| 6 | + * @requires $rootScope |
5 | 7 | *
|
6 |
| - * @param {function(function)=} nextTick Function for executing functions in the next turn. Falls |
7 |
| - * back to `setTimeout` if undefined. |
8 |
| - * @param {function(...*)=} exceptionHandler Function into which unexpected exceptions are passed for |
9 |
| - * debugging purposes. Falls back to `console.error` if undefined, |
10 |
| - * @returns {object} Promise manager. |
| 8 | + * @description |
| 9 | + * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q). |
| 10 | + * |
| 11 | + * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an |
| 12 | + * interface for interacting with an object that represents the result of an action that is |
| 13 | + * performed asynchronously, and may or may not be finished at any given point in time. |
| 14 | + * |
| 15 | + * From the perspective of dealing with error handling, deferred and promise apis are to |
| 16 | + * asynchronous programing what `try`, `catch` and `throw` keywords are to synchronous programing. |
| 17 | + * |
| 18 | + * <pre> |
| 19 | + * // for the purpose of this example let's assume that variables `$q` and `scope` are |
| 20 | + * // available in the current lexical scope (they could have been injected or passed in). |
| 21 | + * |
| 22 | + * function asyncGreet(name) { |
| 23 | + * var deferred = $q.defer(); |
| 24 | + * |
| 25 | + * setTimeout(function() { |
| 26 | + * // since this fn executes async in a future turn of the event loop, we need to wrap |
| 27 | + * // our code into an $apply call so that the model changes are properly observed. |
| 28 | + * scope.$apply(function() { |
| 29 | + * if (okToGreet(name)) { |
| 30 | + * deferred.resolve('Hello, ' + name + '!'); |
| 31 | + * } else { |
| 32 | + * deferred.reject('Greeting ' + name + ' is not allowed.'); |
| 33 | + * } |
| 34 | + * }); |
| 35 | + * }, 1000); |
| 36 | + * |
| 37 | + * return deferred.promise; |
| 38 | + * } |
| 39 | + * |
| 40 | + * var promise = asyncGreet('Robin Hood'); |
| 41 | + * promise.then(function(greeting) { |
| 42 | + * alert('Success: ' + greeting); |
| 43 | + * }, function(reason) { |
| 44 | + * alert('Failed: ' + reason); |
| 45 | + * ); |
| 46 | + * </pre> |
| 47 | + * |
| 48 | + * At first it might not be obvious why this extra complexity is worth the trouble. The payoff |
| 49 | + * comes in the way of |
| 50 | + * [guarantees that promise and deferred apis make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md). |
| 51 | + * |
| 52 | + * Additionally the promise api allows for composition that is very hard to do with the |
| 53 | + * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach. |
| 54 | + * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the |
| 55 | + * section on serial or parallel joining of promises. |
| 56 | + * |
| 57 | + * |
| 58 | + * # The Deferred API |
| 59 | + * |
| 60 | + * A new instance of deferred is constructed by calling `$q.defer()`. |
| 61 | + * |
| 62 | + * The purpose of the deferred object is to expose the associated Promise instance as well as apis |
| 63 | + * that can be used for signaling the successful or unsuccessful completion of the task. |
| 64 | + * |
| 65 | + * **Methods** |
| 66 | + * |
| 67 | + * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection |
| 68 | + * constructed via `$q.reject`, the promise will be rejected instead. |
| 69 | + * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to |
| 70 | + * resolving it with a rejection constructed via `$q.reject`. |
| 71 | + * |
| 72 | + * **Properties** |
| 73 | + * |
| 74 | + * - promise – `{Promise}` – promise object associated with this deferred. |
| 75 | + * |
| 76 | + * |
| 77 | + * # The Promise API |
| 78 | + * |
| 79 | + * A new promise instance is created when a deferred instance is created and can be retrieved by |
| 80 | + * calling `deferred.promise`. |
| 81 | + * |
| 82 | + * The purpose of the promise object is to allow for interested parties to get access to the result |
| 83 | + * of the deferred task when it completes. |
| 84 | + * |
| 85 | + * **Methods** |
| 86 | + * |
| 87 | + * - `then(successCallback, errorCallback)` – regardless of when the promise was or will be resolved |
| 88 | + * or rejected calls one of the success or error callbacks asynchronously as soon as the result |
| 89 | + * is available. The callbacks are called with a single argument the result or rejection reason. |
| 90 | + * |
| 91 | + * This method *returns a new promise* which is resolved or rejected via the return value of the |
| 92 | + * `successCallback` or `errorCallback`. |
| 93 | + * |
| 94 | + * |
| 95 | + * # Chaining promises |
| 96 | + * |
| 97 | + * Because calling `then` api of a promise returns a new derived promise, it is easily possible |
| 98 | + * to create a chain of promises: |
| 99 | + * |
| 100 | + * <pre> |
| 101 | + * promiseB = promiseA.then(function(result) { |
| 102 | + * return result + 1; |
| 103 | + * }); |
| 104 | + * |
| 105 | + * // promiseB will be resolved immediately after promiseA is resolved and it's value will be |
| 106 | + * // the result of promiseA incremented by 1 |
| 107 | + * </pre> |
| 108 | + * |
| 109 | + * It is possible to create chains of any length and since a promise can be resolved with another |
| 110 | + * promise (which will defer its resolution further), it is possible to pause/defer resolution of |
| 111 | + * the promises at any point in the chain. This makes it possible to implement powerful apis like |
| 112 | + * $http's response interceptors. |
| 113 | + * |
| 114 | + * |
| 115 | + * # Differences between Kris Kowal's Q and $q |
| 116 | + * |
| 117 | + * There are three main differences: |
| 118 | + * |
| 119 | + * - $q is integrated with the {@link angular.module.ng.$rootScope.Scope} Scope model observation |
| 120 | + * mechanism in angular, which means faster propagation of resolution or rejection into your |
| 121 | + * models and avoiding unnecessary browser repaints, which would result in flickering UI. |
| 122 | + * - $q promises are recognized by the templating engine in angular, which means that in templates |
| 123 | + * you can treat promises attached to a scope as if they were the resulting values. |
| 124 | + * - Q has many more features that $q, but that comes at a cost of bytes. $q is tiny, but contains |
| 125 | + * all the important functionality needed for common async tasks. |
11 | 126 | */
|
12 |
| -function qFactory(nextTick, exceptionHandler) { |
| 127 | +function $QProvider() { |
13 | 128 |
|
14 |
| - nextTick = nextTick || function(callback) { |
15 |
| - setTimeout(callback, 0); // very rare since most of queueing will be handled within $apply |
16 |
| - }; |
| 129 | + this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) { |
| 130 | + return qFactory(function(callback) { |
| 131 | + $rootScope.$evalAsync(callback); |
| 132 | + }, $exceptionHandler); |
| 133 | + }]; |
| 134 | +} |
17 | 135 |
|
18 |
| - exceptionHandler = exceptionHandler || function(e) { |
19 |
| - // TODO(i): console.error is somehow reset to function(a) {}, it might be a JSTD bug |
20 |
| - if (console && console.log) { |
21 |
| - console.log(e); |
22 |
| - } |
23 |
| - } |
24 | 136 |
|
| 137 | +/** |
| 138 | + * Constructs a promise manager. |
| 139 | + * |
| 140 | + * @param {function(function)} nextTick Function for executing functions in the next turn. |
| 141 | + * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for |
| 142 | + * debugging purposes. |
| 143 | + * @returns {object} Promise manager. |
| 144 | + */ |
| 145 | +function qFactory(nextTick, exceptionHandler) { |
25 | 146 |
|
26 | 147 | /**
|
27 | 148 | * @ngdoc
|
@@ -264,110 +385,3 @@ function qFactory(nextTick, exceptionHandler) {
|
264 | 385 | all: all
|
265 | 386 | };
|
266 | 387 | }
|
267 |
| - |
268 |
| -/** |
269 |
| - * @ngdoc service |
270 |
| - * @name angular.module.ng.$q |
271 |
| - * @requires $rootScope |
272 |
| - * |
273 |
| - * @description |
274 |
| - * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q). |
275 |
| - * |
276 |
| - * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an |
277 |
| - * interface for interacting with an object that represents the result of an action that is |
278 |
| - * performed asynchronously, and may or may not be finished at any given point in time. |
279 |
| - * |
280 |
| - * When it comes to error handling, deferred and promise apis are to asynchronous programing what |
281 |
| - * `try`, `catch` and `throw` keywords are to synchronous programing. |
282 |
| - * |
283 |
| - * <pre> |
284 |
| - * function asyncGreet(name) { |
285 |
| - * var deferred = $q.defer(); |
286 |
| - * |
287 |
| - * setTimeout(function() { |
288 |
| - * if (okToGreet(name)) { |
289 |
| - * deferred.resolve('Hello, ' + name + '!'); |
290 |
| - * } else { |
291 |
| - * deferred.reject('Greeting ' + name + ' is not allowed.'); |
292 |
| - * } |
293 |
| - * }, 1000); |
294 |
| - * |
295 |
| - * return deferred.promise; |
296 |
| - * } |
297 |
| - * |
298 |
| - * var promise = asyncGreet('Robin Hood'); |
299 |
| - * promise.then(function(greeting) { |
300 |
| - * alert('Success: ' + greeting); |
301 |
| - * }, function(reason) { |
302 |
| - * alert('Failed: ' + reason); |
303 |
| - * ); |
304 |
| - * </pre> |
305 |
| - * |
306 |
| - * At first it might not be obvious why this extra complexity is worth the trouble. The payoff |
307 |
| - * comes in the way of |
308 |
| - * [guarantees that promise and deferred apis make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md). |
309 |
| - * |
310 |
| - * Additionally the promise api allows for composition that is very hard to do with the |
311 |
| - * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach. |
312 |
| - * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the |
313 |
| - * section on serial or paralel joining of promises. |
314 |
| - * |
315 |
| - * |
316 |
| - * # The Deferred API |
317 |
| - * |
318 |
| - * A new instance of deferred is constructed by calling `$q.defer()`. |
319 |
| - * |
320 |
| - * The purpose of the deferred object is to expose the associated Promise instance as well as api's |
321 |
| - * that can be used for singnaling the successful or unsucessful completion of the task. |
322 |
| - * |
323 |
| - * **Methods** |
324 |
| - * |
325 |
| - * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection |
326 |
| - * constructed via `$q.reject`, the promise will be rejected instead. |
327 |
| - * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to |
328 |
| - * resolving it with a rejection constructed via `$q.reject`. |
329 |
| - * |
330 |
| - * **Properties** |
331 |
| - * |
332 |
| - * - promise – `{Promise}` – promise object associated with this deferred. |
333 |
| - * |
334 |
| - * |
335 |
| - * # The Promise API |
336 |
| - * |
337 |
| - * A new promise instance is created when a deferred instance is created and can be retrieved by |
338 |
| - * calling `deferred.promise`. |
339 |
| - * |
340 |
| - * The purpose of the promise object is to allow for interested parties to get access to the result |
341 |
| - * of the deferred task when it completes. |
342 |
| - * |
343 |
| - * **Methods** |
344 |
| - * |
345 |
| - * - `then(successCallback, errorCallback)` – regardless of when the promise was or will be resolved |
346 |
| - * or rejected calls one of the success or error callbacks asynchronously as soon as the result |
347 |
| - * is available. |
348 |
| - * |
349 |
| - * This method *returns a new promise* which is resolved or rejected via the return value of the |
350 |
| - * `successCallback` or `errorCallback`. |
351 |
| - * |
352 |
| - * |
353 |
| - * # Differences betweeb Kris Kowal's Q and $q |
354 |
| - * |
355 |
| - * There are three main differences: |
356 |
| - * |
357 |
| - * - $q is integrated with the {@link angular.module.ng.$rootScope.Scope} Scope model observation |
358 |
| - * mechanism in angular, which means faster propagation of resolution or rejection into your |
359 |
| - * models and avoiding unnecessary browser redraws, which would result in flickering UI. |
360 |
| - * - $q promises are reconginized by the templating engine in angular, which means that in templates |
361 |
| - * you can treat promises attached to a scope as if they were the resulting values. |
362 |
| - * - Q has many more features that $q, but that comes at a cost of bytes. $q is tiny, but contains |
363 |
| - * all the important functionality needed for common async tasks. |
364 |
| - */ |
365 |
| -// TODO(i): move elsewhere |
366 |
| -function $QProvider() { |
367 |
| - |
368 |
| - this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) { |
369 |
| - return qFactory(function(callback) { |
370 |
| - $rootScope.$evalAsync(callback); |
371 |
| - }, $exceptionHandler); |
372 |
| - }]; |
373 |
| -} |
|
0 commit comments