@angular-wave/angular.ts 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/angular-ts.esm.js +2 -2
  2. package/dist/angular-ts.umd.js +12 -2
  3. package/index.html +74 -3
  4. package/package.json +7 -7
  5. package/src/angular.spec.js +1 -269
  6. package/src/animations/animate-css-driver.js +2 -2
  7. package/src/animations/animate-css.js +12 -21
  8. package/src/animations/animate-js-driver.js +1 -3
  9. package/src/animations/animate-js.js +4 -4
  10. package/src/animations/animate-queue.js +23 -23
  11. package/src/animations/animate-runner.js +4 -8
  12. package/src/animations/animate.md +1 -1
  13. package/src/animations/animate.spec.js +0 -21
  14. package/src/animations/animation.js +4 -4
  15. package/src/animations/shared.js +14 -12
  16. package/src/binding.spec.js +0 -1
  17. package/src/core/cache/cache.js +2 -29
  18. package/src/core/compile/attributes.js +2 -3
  19. package/src/core/compile/compile.js +260 -245
  20. package/src/core/compile/compile.spec.js +63 -317
  21. package/src/core/compile/compile.test.js +1 -1
  22. package/src/core/controller/controller.js +2 -0
  23. package/src/core/di/injector.md +1 -1
  24. package/src/core/di/injector.spec.js +0 -2
  25. package/src/core/di/internal-injector.js +2 -1
  26. package/src/core/interpolate/interpolate.js +16 -3
  27. package/src/core/interpolate/interpolate.spec.js +70 -16
  28. package/src/core/location/location.js +0 -2
  29. package/src/core/location/location.spec.js +27 -27
  30. package/src/core/{scope/scope.html → model/model.html} +1 -1
  31. package/src/core/model/model.js +944 -0
  32. package/src/core/model/model.spec.js +3012 -0
  33. package/src/core/on.spec.js +0 -7
  34. package/src/core/parse/interpreter.js +10 -7
  35. package/src/core/parse/parse.js +28 -7
  36. package/src/core/parse/parse.spec.js +95 -91
  37. package/src/core/prop.spec.js +4 -60
  38. package/src/core/sce/sce.js +1 -2
  39. package/src/core/sce/sce.spec.js +0 -8
  40. package/src/core/scope/scope.js +62 -32
  41. package/src/core/scope/scope.spec.js +25 -1960
  42. package/src/directive/aria/aria.js +3 -6
  43. package/src/directive/aria/aria.spec.js +0 -87
  44. package/src/directive/attrs/attrs.spec.js +0 -5
  45. package/src/directive/{list/list.test.js → attrs/attrs.test.js} +1 -1
  46. package/src/{core/q/q.html → directive/attrs/boolean.html} +1 -1
  47. package/src/directive/attrs/boolean.spec.js +0 -15
  48. package/src/{core/q/q.test.js → directive/attrs/boolean.test.js} +1 -2
  49. package/src/{core/timeout/timeout.html → directive/attrs/element-style.html} +4 -1
  50. package/src/directive/attrs/element-style.spec.js +0 -8
  51. package/src/{core/scope/scope.test.js → directive/attrs/element-style.test.js} +1 -2
  52. package/src/directive/attrs/src.spec.js +0 -7
  53. package/src/directive/bind/bind.spec.js +0 -33
  54. package/src/directive/bind/bing-html.spec.js +1 -4
  55. package/src/{core/interval/interval.html → directive/channel/channel.html} +1 -1
  56. package/src/directive/channel/channel.js +29 -0
  57. package/src/directive/channel/channel.spec.js +52 -0
  58. package/src/directive/channel/channel.test.js +9 -0
  59. package/src/directive/class/class.js +3 -3
  60. package/src/directive/class/class.spec.js +9 -75
  61. package/src/directive/controller/controller.spec.js +0 -13
  62. package/src/directive/events/click.spec.js +0 -3
  63. package/src/directive/events/event.spec.js +0 -6
  64. package/src/directive/form/form.js +14 -22
  65. package/src/directive/form/form.spec.js +0 -65
  66. package/src/directive/if/if.spec.js +2 -7
  67. package/src/directive/if/if.test.js +1 -2
  68. package/src/directive/include/include.js +2 -2
  69. package/src/directive/include/include.spec.js +8 -59
  70. package/src/directive/init/init.js +6 -2
  71. package/src/directive/init/init.spec.js +0 -2
  72. package/src/directive/input/input.js +1 -2
  73. package/src/directive/input/input.spec.js +191 -331
  74. package/src/directive/messages/messages.spec.js +4 -35
  75. package/src/directive/model/model.js +30 -42
  76. package/src/directive/model/model.spec.js +2 -49
  77. package/src/directive/model-options/model-options.js +22 -26
  78. package/src/directive/model-options/model-options.spec.js +0 -6
  79. package/src/directive/non-bindable/non-bindable.spec.js +0 -1
  80. package/src/directive/observe/observe.js +0 -1
  81. package/src/directive/observe/observe.spec.js +0 -1
  82. package/src/directive/options/options.js +1 -3
  83. package/src/directive/options/options.spec.js +3 -38
  84. package/src/directive/ref/href.spec.js +0 -15
  85. package/src/directive/repeat/repeat.js +2 -2
  86. package/src/directive/repeat/repeat.spec.js +56 -192
  87. package/src/directive/script/script.spec.js +0 -2
  88. package/src/directive/select/select.js +3 -3
  89. package/src/directive/select/select.spec.js +9 -106
  90. package/src/directive/show-hide/show-hide.js +2 -2
  91. package/src/directive/show-hide/show-hide.spec.js +8 -19
  92. package/src/directive/style/style.spec.js +0 -7
  93. package/src/directive/switch/switch.js +1 -2
  94. package/src/directive/switch/switch.spec.js +5 -5
  95. package/src/directive/validators/validators.spec.js +0 -1
  96. package/src/loader.js +0 -1
  97. package/src/public.js +75 -80
  98. package/src/router/common/coreservices.js +0 -2
  99. package/src/router/directives/state-directives.js +24 -30
  100. package/src/router/directives/state-directives.spec.js +0 -83
  101. package/src/router/directives/view-directive.js +6 -15
  102. package/src/router/directives/view-directive.spec.js +25 -71
  103. package/src/router/hooks/lazy-load.js +2 -2
  104. package/src/router/hooks/views.js +3 -5
  105. package/src/router/resolve/resolvable.js +3 -6
  106. package/src/router/resolve/resolve-context.js +2 -2
  107. package/src/router/state/state-service.js +4 -4
  108. package/src/router/state/state.spec.js +2 -5
  109. package/src/router/state/views.js +9 -12
  110. package/src/router/template-factory.js +3 -6
  111. package/src/router/template-factory.spec.js +0 -4
  112. package/src/router/transition/transition-hook.js +1 -1
  113. package/src/router/transition/transition.js +1 -1
  114. package/src/router/url/url-service.js +2 -8
  115. package/src/router/url/url-service.spec.js +3 -4
  116. package/src/router/view-hook.spec.js +2 -2
  117. package/src/router/view-scroll.js +4 -6
  118. package/src/services/http/http.js +11 -15
  119. package/src/services/http/http.spec.js +30 -31
  120. package/src/services/http/template-request.spec.js +0 -10
  121. package/src/services/http-backend/http-backend.js +19 -17
  122. package/src/services/http-backend/http-backend.spec.js +3 -3
  123. package/src/services/template-request.js +2 -4
  124. package/src/shared/common.js +6 -10
  125. package/src/shared/jqlite/jqlite.js +14 -15
  126. package/src/shared/jqlite/jqlite.spec.js +2 -2
  127. package/src/shared/utils.js +15 -92
  128. package/types/core/cache/cache.d.ts +1 -1
  129. package/types/core/model/model.d.ts +204 -0
  130. package/types/core/parse/parse.d.ts +26 -0
  131. package/types/core/scope/scope.d.ts +22 -21
  132. package/types/directive/channel/channel.d.ts +11 -0
  133. package/types/directive/form/form.d.ts +1 -0
  134. package/types/shared/common.d.ts +0 -1
  135. package/types/shared/utils.d.ts +0 -35
  136. package/src/core/interval/interval-factory.js +0 -50
  137. package/src/core/interval/interval.js +0 -77
  138. package/src/core/interval/interval.md +0 -123
  139. package/src/core/interval/interval.spec.js +0 -280
  140. package/src/core/q/q.js +0 -472
  141. package/src/core/q/q.md +0 -211
  142. package/src/core/q/q.spec.js +0 -2748
  143. package/src/core/timeout/timeout.js +0 -109
  144. package/src/core/timeout/timeout.spec.js +0 -354
  145. package/src/core/timeout/timout.test.js +0 -12
  146. package/src/directive/list/list.html +0 -18
  147. package/src/directive/list/list.js +0 -46
  148. package/src/directive/list/list.md +0 -22
  149. package/src/directive/list/list.spec.js +0 -172
  150. package/types/directive/list/list.d.ts +0 -4
package/src/core/q/q.js DELETED
@@ -1,472 +0,0 @@
1
- import {
2
- minErr,
3
- isUndefined,
4
- isFunction,
5
- isObject,
6
- isDefined,
7
- isError,
8
- toDebugString,
9
- isPromiseLike,
10
- } from "../../shared/utils";
11
-
12
- /**
13
- * @typedef {Object} QService
14
- * @property {function():Deferred<any>} defer
15
- * @property {function(any?):QPromise<any>} all
16
- * @property {function(any?):any} resolve
17
- * @property {function(any):any} reject
18
- */
19
-
20
- /**
21
- * @typedef {Object} PromiseState
22
- * @property {?number} status
23
- * @property {PromiseResolvables[]} [pending]
24
- * @property {boolean} processScheduled
25
- * @property {any} [value]
26
- * @property {boolean} pur
27
- */
28
-
29
- /**
30
- * @typedef {Object} PromiseResolvables
31
- * @property {any} result
32
- * @property {function(any):any} onFulfilled
33
- * @property {function(any):any} onRejected
34
- */
35
-
36
- /**
37
- * @template T
38
- * @typedef {Object} QPromise
39
- * @property {function(any,any?): QPromise<T|never>} then - Calls one of the success or error callbacks asynchronously as soon as the result is available.
40
- * @property {function(((reason: any) => (PromiseLike<never>|PromiseLike<T>|T))|null): QPromise<T>|T} catch - Shorthand for promise.then(null, errorCallback).
41
- * @property {function(((reason: any) => (QPromise<never>|QPromise<T>|T))|null): QPromise<T>|T} catch - Shorthand for promise.then(null, errorCallback).
42
- * @property {function(Array.<QPromise<T>>): QPromise<T>} all
43
- * @property {function(function(): void): QPromise<T>} finally - Allows you to observe either the fulfillment or rejection of a promise, but to do so without modifying the final value.
44
- * @property {number} [$$intervalId] - Internal id set by the $interval service for callback notifications
45
- * @property {number} [$$timeoutId] - Timeout id set by the $timeout service for cancelations
46
- */
47
-
48
- /**
49
- *@template T
50
- * @typedef {Object} Deferred
51
- * @property {function(T|QPromise<T>): void} resolve - Resolves the promise with a value or another promise.
52
- * @property {function(any): void} reject - Rejects the promise with a reason.
53
- * @property {function(any): void} notify - Provides a progress notification.
54
- * @property {QPromise<T>} promise - The promise associated with this deferred object.
55
- */
56
-
57
- export class $QProvider {
58
- constructor() {
59
- this.errorOn = true;
60
- }
61
-
62
- $get = [
63
- "$rootScope",
64
- "$exceptionHandler",
65
- /**
66
- *
67
- * @param {import('../scope/scope').Scope} $rootScope
68
- * @param {import('../exception-handler').ErrorHandler} $exceptionHandler
69
- * @returns
70
- */
71
- function ($rootScope, $exceptionHandler) {
72
- return qFactory(
73
- (callback) => {
74
- $rootScope.$evalAsync(
75
- /** @type {function(function):any} */ (callback),
76
- );
77
- },
78
- $exceptionHandler,
79
- this.errorOn,
80
- );
81
- },
82
- ];
83
-
84
- /**
85
- * Retrieves or overrides whether to generate an error when a rejected promise is not handled.
86
- * This feature is enabled by default.
87
- *
88
- * @param {boolean=} value Whether to generate an error when a rejected promise is not handled.
89
- * @returns {boolean|$QProvider} Current value when called without a new value or self for
90
- * chaining otherwise.
91
- */
92
- errorOnUnhandledRejections(value) {
93
- if (isDefined(value)) {
94
- this.errorOn = value;
95
- return this;
96
- }
97
- return this.errorOn;
98
- }
99
- }
100
-
101
- /**
102
- * Constructs a promise manager.
103
- *
104
- * @param {function(function):any} nextTick Function for executing functions in the next turn.
105
- * @param {function(...any):any} exceptionHandler Function into which unexpected exceptions are passed for
106
- * debugging purposes.
107
- * @param {boolean=} errorOnUnhandledRejections Whether an error should be generated on unhandled
108
- * promises rejections.
109
- * @returns {object} Promise manager.
110
- */
111
- function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
112
- const $qMinErr = minErr("$q");
113
- let queueSize = 0;
114
- /**
115
- * @type {PromiseState[]}
116
- */
117
- const checkQueue = [];
118
-
119
- class Deferred {
120
- constructor() {
121
- this.promise = new QPromise();
122
- this.resolve = (val) => resolvePromise(this.promise, val);
123
- this.reject = (reason) => rejectPromise(this.promise, reason);
124
- }
125
- }
126
-
127
- class QPromise {
128
- constructor() {
129
- /** @type {PromiseState} */
130
- this.$$state = {
131
- status: 0,
132
- pending: undefined,
133
- processScheduled: false,
134
- pur: false,
135
- };
136
- }
137
-
138
- /**
139
- * Calls one of the success or error callbacks asynchronously as soon as the result is available.
140
- * @param {*} onFulfilled
141
- * @param {*} onRejected
142
- * @returns
143
- */
144
- then(onFulfilled, onRejected) {
145
- if (isUndefined(onFulfilled) && isUndefined(onRejected)) {
146
- return this;
147
- }
148
- const result = new QPromise();
149
-
150
- this.$$state.pending = this.$$state.pending || [];
151
- this.$$state.pending.push({
152
- result: result,
153
- onFulfilled: onFulfilled,
154
- onRejected: onRejected,
155
- });
156
- if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
157
-
158
- return result;
159
- }
160
-
161
- catch(callback) {
162
- return this.then(null, callback);
163
- }
164
-
165
- finally(callback) {
166
- return this.then(
167
- (value) => handleCallback(value, resolve, callback),
168
- (error) => handleCallback(error, reject, callback),
169
- );
170
- }
171
- }
172
-
173
- /**
174
- * @param {PromiseState} state
175
- */
176
- function processQueue(state) {
177
- state.processScheduled = false;
178
- try {
179
- for (let i = 0, ii = state.pending.length; i < ii; ++i) {
180
- state.pur = true;
181
- const promise = state.pending[i].result;
182
- let fn;
183
- if (state.status === 1) {
184
- fn = state.pending[i].onFulfilled;
185
- } else {
186
- fn = state.pending[i].onRejected;
187
- }
188
- try {
189
- if (isFunction(fn)) {
190
- resolvePromise(promise, fn(state.value));
191
- } else if (state.status === 1) {
192
- resolvePromise(promise, state.value);
193
- } else {
194
- rejectPromise(promise, state.value);
195
- }
196
- } catch (e) {
197
- rejectPromise(promise, e);
198
- }
199
- }
200
- } finally {
201
- --queueSize;
202
- if (errorOnUnhandledRejections && queueSize === 0) {
203
- nextTick(processChecks);
204
- }
205
- state.pending = undefined;
206
- }
207
- }
208
-
209
- function processChecks() {
210
- while (!queueSize && checkQueue.length) {
211
- const toCheck = checkQueue.shift();
212
- if (!isStateExceptionHandled(toCheck)) {
213
- toCheck.pur = true;
214
- const errorMessage = `Possibly unhandled rejection: ${toDebugString(toCheck.value)}`;
215
- if (isError(toCheck.value)) {
216
- exceptionHandler(toCheck.value, errorMessage);
217
- } else {
218
- exceptionHandler(errorMessage);
219
- }
220
- }
221
- }
222
- }
223
-
224
- /**
225
- * @param {PromiseState} state
226
- */
227
- function scheduleProcessQueue(state) {
228
- if (
229
- errorOnUnhandledRejections &&
230
- !state.pending &&
231
- state.status === 2 &&
232
- !isStateExceptionHandled(state)
233
- ) {
234
- if (queueSize === 0 && checkQueue.length === 0) {
235
- nextTick(processChecks);
236
- }
237
- checkQueue.push(state);
238
- }
239
- if (state.processScheduled || !state.pending) return;
240
- state.processScheduled = true;
241
- ++queueSize;
242
- nextTick(() => {
243
- processQueue(state);
244
- });
245
- }
246
-
247
- /**
248
- * @param {QPromise} promise
249
- * @param {*} val
250
- * @returns
251
- */
252
- function resolvePromise(promise, val) {
253
- if (promise.$$state.status) return;
254
- if (val === promise) {
255
- $$reject(
256
- promise,
257
- $qMinErr(
258
- "qcycle",
259
- "Expected promise to be resolved with value other than itself '{0}'",
260
- val,
261
- ),
262
- );
263
- } else {
264
- $$resolve(promise, val);
265
- }
266
- }
267
-
268
- /**
269
- *
270
- * @param {QPromise} promise
271
- * @param {*} val
272
- */
273
- function $$resolve(promise, val) {
274
- let then;
275
- let done = false;
276
- try {
277
- if (isObject(val) || isFunction(val)) then = val.then;
278
- if (isFunction(then)) {
279
- promise.$$state.status = -1;
280
- then.call(val, doResolve, doReject);
281
- } else {
282
- promise.$$state.value = val;
283
- promise.$$state.status = 1;
284
- scheduleProcessQueue(promise.$$state);
285
- }
286
- } catch (e) {
287
- doReject(e);
288
- }
289
-
290
- function doResolve(val) {
291
- if (done) return;
292
- done = true;
293
- $$resolve(promise, val);
294
- }
295
- function doReject(val) {
296
- if (done) return;
297
- done = true;
298
- $$reject(promise, val);
299
- }
300
- }
301
-
302
- /**
303
- * @param {QPromise} promise
304
- * @param {*} reason
305
- * @returns
306
- */
307
- function rejectPromise(promise, reason) {
308
- if (promise.$$state.status) return;
309
- $$reject(promise, reason);
310
- }
311
-
312
- /**
313
- * @param {QPromise} promise
314
- * @param {*} reason
315
- * @returns
316
- */
317
- function $$reject(promise, reason) {
318
- promise.$$state.value = reason;
319
- promise.$$state.status = 2;
320
- scheduleProcessQueue(promise.$$state);
321
- }
322
-
323
- /**
324
- * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
325
- * used to forward rejection in a chain of promises. If you are dealing with the last promise in
326
- * a promise chain, you don't need to worry about it.
327
- *
328
- * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
329
- * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
330
- * a promise error callback and you want to forward the error to the promise derived from the
331
- * current promise, you have to "rethrow" the error by returning a rejection constructed via
332
- * `reject`.
333
- * ```
334
- *
335
- * @param {*} reason Constant, message, exception or an object representing the rejection reason.
336
- * @returns {QPromise} Returns a promise that was already resolved as rejected with the `reason`.
337
- */
338
- function reject(reason) {
339
- const result = new QPromise();
340
- rejectPromise(result, reason);
341
- return result;
342
- }
343
-
344
- function handleCallback(value, resolver, callback) {
345
- let callbackOutput = null;
346
- try {
347
- if (isFunction(callback)) callbackOutput = callback();
348
- } catch (e) {
349
- return reject(e);
350
- }
351
- if (isPromiseLike(callbackOutput)) {
352
- return callbackOutput.then(() => resolver(value), reject);
353
- }
354
- return resolver(value);
355
- }
356
-
357
- /**
358
- * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
359
- * This is useful when you are dealing with an object that might or might not be a promise, or if
360
- * the promise comes from a source that can't be trusted.
361
- *
362
- * @param {*} value Value or a promise
363
- * @param {Function=} successCallback
364
- * @param {Function=} errorCallback
365
- * @returns {QPromise} Returns a promise of the passed value or promise
366
- */
367
-
368
- function resolve(value, successCallback, errorCallback) {
369
- const result = new QPromise();
370
- resolvePromise(result, value);
371
- return result.then(successCallback, errorCallback);
372
- }
373
-
374
- /**
375
- * Combines multiple promises into a single promise that is resolved when all of the input
376
- * promises are resolved.
377
- *
378
- * @param {Array.<QPromise>} promises An array or hash of promises.
379
- * @returns {QPromise} Returns a single promise that will be resolved with an array/hash of values,
380
- * each value corresponding to the promise at the same index/key in the `promises` array/hash.
381
- * If any of the promises is resolved with a rejection, this resulting promise will be rejected
382
- * with the same rejection value.
383
- */
384
-
385
- function all(promises) {
386
- const result = new QPromise();
387
- let counter = 0;
388
- const results = Array.isArray(promises) ? [] : {};
389
-
390
- Object.entries(promises).forEach(([key, promise]) => {
391
- counter++;
392
- resolve(promise).then(
393
- (value) => {
394
- results[key] = value;
395
- if (!--counter) resolvePromise(result, results);
396
- },
397
- (reason) => {
398
- rejectPromise(result, reason);
399
- },
400
- );
401
- });
402
-
403
- if (counter === 0) {
404
- resolvePromise(result, results);
405
- }
406
-
407
- return result;
408
- }
409
-
410
- /**
411
- * Returns a promise that resolves or rejects as soon as one of those promises
412
- * resolves or rejects, with the value or reason from that promise.
413
- *
414
- * @param {Array.<QPromise>} promises An array or hash of promises.
415
- * @returns {QPromise} a promise that resolves or rejects as soon as one of the `promises`
416
- * resolves or rejects, with the value or reason from that promise.
417
- */
418
-
419
- function race(promises) {
420
- const deferred = new Deferred();
421
-
422
- promises.forEach((promise) => {
423
- resolve(promise).then(deferred.resolve, deferred.reject);
424
- });
425
-
426
- return deferred.promise;
427
- }
428
-
429
- /**
430
- * @param {function(function, function):any} resolver Function which is responsible for resolving or
431
- * rejecting the newly created promise. The first parameter is a function which resolves the
432
- * promise, the second parameter is a function which rejects the promise.
433
- *
434
- * @returns {QPromise} The newly created promise.
435
- */
436
- function $Q(resolver) {
437
- if (!isFunction(resolver)) {
438
- throw $qMinErr("norslvr", "Expected resolverFn, got '{0}'", resolver);
439
- }
440
-
441
- const promise = new QPromise();
442
-
443
- resolver(
444
- (value) => resolvePromise(promise, value),
445
- (reason) => rejectPromise(promise, reason),
446
- );
447
-
448
- return promise;
449
- }
450
-
451
- $Q.defer = () => new Deferred();
452
- $Q.reject = reject;
453
- $Q.resolve = resolve;
454
- $Q.all = all;
455
- $Q.race = race;
456
-
457
- return $Q;
458
- }
459
-
460
- function isStateExceptionHandled(state) {
461
- return !!state.pur;
462
- }
463
-
464
- export function markQExceptionHandled(q) {
465
- // Built-in `$q` promises will always have a `$$state` property. This check is to allow
466
- // overwriting `$q` with a different promise library (e.g. Bluebird + angular-bluebird-promises).
467
- // (Currently, this is the only method that might be called with a promise, even if it is not
468
- // created by the built-in `$q`.)
469
- if (q.$$state) {
470
- q.$$state.pur = true;
471
- }
472
- }
package/src/core/q/q.md DELETED
@@ -1,211 +0,0 @@
1
- /\*\*
2
-
3
- - A service that helps you run functions asynchronously, and use their return values (or exceptions)
4
- - when they are done processing.
5
- -
6
- - This is a [Promises/A+](https://promisesaplus.com/)-compliant implementation of promises/deferred
7
- - objects inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
8
- -
9
- - $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
10
- - implementations, and the other which resembles ES6 (ES2015) promises to some degree.
11
- -
12
- - ## $q constructor
13
- -
14
- - The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
15
- - function as the first argument. This is similar to the native Promise implementation from ES6,
16
- - see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
17
- -
18
- - While the constructor-style use is supported, not all of the supporting methods from ES6 promises are
19
- - available yet.
20
- -
21
- - It can be used like so:
22
- -
23
- - ```js
24
-
25
- ```
26
-
27
- - // for the purpose of this example let's assume that variables `$q` and `okToGreet`
28
- - // are available in the current lexical scope (they could have been injected or passed in).
29
- -
30
- - function asyncGreet(name) {
31
- - // perform some asynchronous operation, resolve or reject the promise when appropriate.
32
- - return $q(function(resolve, reject) {
33
- - setTimeout(function() {
34
- - if (okToGreet(name)) {
35
- - resolve('Hello, ' + name + '!');
36
- - } else {
37
- - reject('Greeting ' + name + ' is not allowed.');
38
- - }
39
- - }, 1000);
40
- - });
41
- - }
42
- -
43
- - let promise = asyncGreet('Robin Hood');
44
- - promise.then(function(greeting) {
45
- - alert('Success: ' + greeting);
46
- - }, function(reason) {
47
- - alert('Failed: ' + reason);
48
- - });
49
- - ```
50
-
51
- ```
52
-
53
- -
54
- - Note: progress/notify callbacks are not currently supported via the ES6-style interface.
55
- -
56
- - Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
57
- -
58
- - However, the more traditional CommonJS-style usage is still available, and documented below.
59
- -
60
- - [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
61
- - interface for interacting with an object that represents the result of an action that is
62
- - performed asynchronously, and may or may not be finished at any given point in time.
63
- -
64
- - From the perspective of dealing with error handling, deferred and promise APIs are to
65
- - asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
66
- -
67
- - ```js
68
-
69
- ```
70
-
71
- -
72
- - let promise = asyncGreet('Robin Hood');
73
- - promise.then(function(greeting) {
74
- - alert('Success: ' + greeting);
75
- - }, function(reason) {
76
- - alert('Failed: ' + reason);
77
- - }, function(update) {
78
- - alert('Got notification: ' + update);
79
- - });
80
- - ```
81
-
82
- ```
83
-
84
- -
85
- - At first it might not be obvious why this extra complexity is worth the trouble. The payoff
86
- - comes in the way of guarantees that promise and deferred APIs make, see
87
- - https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
88
- -
89
- - Additionally the promise api allows for composition that is very hard to do with the
90
- - traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
91
- - For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
92
- - section on serial or parallel joining of promises.
93
- -
94
- - ## The Deferred API
95
- -
96
- - A new instance of deferred is constructed by calling `$q.defer()`.
97
- -
98
- - The purpose of the deferred object is to expose the associated Promise instance as well as APIs
99
- - that can be used for signaling the successful or unsuccessful completion, as well as the status
100
- - of the task.
101
- -
102
- - **Methods**
103
- -
104
- - - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
105
- - constructed via `$q.reject`, the promise will be rejected instead.
106
- - - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
107
- - resolving it with a rejection constructed via `$q.reject`.
108
- - - `notify(value)` - provides updates on the status of the promise's execution. This may be called
109
- - multiple times before the promise is either resolved or rejected.
110
- -
111
- - **Properties**
112
- -
113
- - - promise – `{Promise}` – promise object associated with this deferred.
114
- -
115
- -
116
- - ## The Promise API
117
- -
118
- - A new promise instance is created when a deferred instance is created and can be retrieved by
119
- - calling `deferred.promise`.
120
- -
121
- - The purpose of the promise object is to allow for interested parties to get access to the result
122
- - of the deferred task when it completes.
123
- -
124
- - **Methods**
125
- -
126
- - - `then(successCallback, [errorCallback], [notifyCallback])` – regardless of when the promise was or
127
- - will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
128
- - as soon as the result is available. The callbacks are called with a single argument: the result
129
- - or rejection reason. Additionally, the notify callback may be called zero or more times to
130
- - provide a progress indication, before the promise is resolved or rejected.
131
- -
132
- - This method _returns a new promise_ which is resolved or rejected via the return value of the
133
- - `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
134
- - with the value which is resolved in that promise using
135
- - [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
136
- - It also notifies via the return value of the `notifyCallback` method. The promise cannot be
137
- - resolved or rejected from the notifyCallback method. The errorCallback and notifyCallback
138
- - arguments are optional.
139
- -
140
- - - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
141
- -
142
- - - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
143
- - but to do so without modifying the final value. This is useful to release resources or do some
144
- - clean-up that needs to be done whether the promise was rejected or resolved. See the [full
145
- - specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
146
- - more information.
147
- -
148
- - ## Chaining promises
149
- -
150
- - Because calling the `then` method of a promise returns a new derived promise, it is easily
151
- - possible to create a chain of promises:
152
- -
153
- - ```js
154
-
155
- ```
156
-
157
- - promiseB = promiseA.then(function(result) {
158
- - return result + 1;
159
- - });
160
- -
161
- - // promiseB will be resolved immediately after promiseA is resolved and its value
162
- - // will be the result of promiseA incremented by 1
163
- - ```
164
-
165
- ```
166
-
167
- -
168
- - It is possible to create chains of any length and since a promise can be resolved with another
169
- - promise (which will defer its resolution further), it is possible to pause/defer resolution of
170
- - the promises at any point in the chain. This makes it possible to implement powerful APIs like
171
- - $http's response interceptors.
172
- -
173
- -
174
- - ## Differences between Kris Kowal's Q and $q
175
- -
176
- - There are two main differences:
177
- -
178
- - - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
179
- - mechanism in AngularJS, which means faster propagation of resolution or rejection into your
180
- - models and avoiding unnecessary browser repaints, which would result in flickering UI.
181
- - - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
182
- - all the important functionality needed for common async tasks.
183
- -
184
- - ## Testing
185
- -
186
- - ```js
187
-
188
- ```
189
-
190
- - it('should simulate promise', inject(function($q, $rootScope) {
191
- - let deferred = $q.defer();
192
- - let promise = deferred.promise;
193
- - let resolvedValue;
194
- -
195
- - promise.then(function(value) { resolvedValue = value; });
196
- - expect(resolvedValue).toBeUndefined();
197
- -
198
- - // Simulate resolving of promise
199
- - deferred.resolve(123);
200
- - // Note that the 'then' function does not get called synchronously.
201
- - // This is because we want the promise API to always be async, whether or not
202
- - // it got called synchronously or asynchronously.
203
- - expect(resolvedValue).toBeUndefined();
204
- -
205
- - // Propagate promise resolution to 'then' functions using $apply().
206
- - $rootScope.$apply();
207
- - expect(resolvedValue).toEqual(123);
208
- - }));
209
- - ```
210
- */
211
- ```