angular/angular.js — pull request #2223 by caiotoon (2013-03-25 12:06:35+00:00)
Title: feat($q): added support to promise notification

It is now possible to notify a promise through deferred.notify() method. Notifications are useful to provide a way to send progress information to promise holders.

As there is many heavy async operation, I also see a increasingly need of reporting progress so user receive feedback. Currently, one of the best ways to cover this necessity is using callbacks. As AngularJS is based on Kris Kowal promise model, I propose the implementation of [Kris Kowal's Progress Notification feature](https://github.com/kriskowal/q#progress-notification).

I've tried to follow both Kris Kowal and Angular $q philosophies. I know there is the necessity to update the DOCs, but I'd like to first discuss the implementation. As we get it done, I'll them update the docs and include in this PR.

First of, although it's a big DIFF, most of the added lines are test cases. I'd like to know from core team if the test cases covers all necessities for such a feature. Also, explaining lightly, I added the method `.notify()` to the deferred, based on Kris Kowal's. This method is pretty simple and do pretty much the same thing as the original: **[call all callbacks in the nextTick](https://github.com/caiotoon/angular.js/blob/5192e973be316dcc66d3330fcbe2e9a1c054afe3/src/ng/q.js#L210-L224)**.

Some of the points, tough, I had to make a decision regarding the behavior, and these are the points I'd like to discuss. The main one are:

1. As `reject`, `notify` [does not defer the progress when receiving a promise](https://github.com/caiotoon/angular.js/blob/5192e973be316dcc66d3330fcbe2e9a1c054afe3/test/ng/qSpec.js#L423-L430) as argument, it simple notify the promise it received as is.
2. [As Kris Kowal's test case](https://github.com/kriskowal/q/blob/master/spec/q-spec.js#L346-L369), we [do not save and re-emit progress notifications](https://github.com/caiotoon/angular.js/blob/5192e973be316dcc66d3330fcbe2e9a1c054afe3/test/ng/qSpec.js#L454-L465).
3. [As Kris Kowal's](https://github.com/kriskowal/q/blob/master/spec/q-spec.js#L314-L344), we [do not notify after fulfillment or rejection](https://github.com/caiotoon/angular.js/blob/5192e973be316dcc66d3330fcbe2e9a1c054afe3/test/ng/qSpec.js#L386-L420).
4. In case of error while notifying, [we stop notification in derived promises](https://github.com/caiotoon/angular.js/blob/5192e973be316dcc66d3330fcbe2e9a1c054afe3/test/ng/qSpec.js#L637-L646), although we still [call all parallel callbacks in the order they were registered with the original value](https://github.com/caiotoon/angular.js/blob/5192e973be316dcc66d3330fcbe2e9a1c054afe3/test/ng/qSpec.js#L573-L582).
5. When using `$q.when()`, the listeners [are attached only on the nextTick](https://github.com/caiotoon/angular.js/blob/5192e973be316dcc66d3330fcbe2e9a1c054afe3/src/ng/q.js#L379-L391). This means that if the notification goes synchronous, we'll lose it, as we don't re-emit notification. Is this correct? Should we change promise behavior someway without braking any test?
6. When using `$q.all()`, we do not await for all promises to notify, instead, [we defer the notification to `nextTick` and notify all notifications received](https://github.com/caiotoon/angular.js/blob/5192e973be316dcc66d3330fcbe2e9a1c054afe3/src/ng/q.js#L438-L448), passing [null if there was no notification for a specific promise](https://github.com/caiotoon/angular.js/blob/5192e973be316dcc66d3330fcbe2e9a1c054afe3/test/ng/qSpec.js#L978-L989), or [omitting the property in case of hashes](https://github.com/caiotoon/angular.js/blob/5192e973be316dcc66d3330fcbe2e9a1c054afe3/test/ng/qSpec.js#L1065-L1083). Is this behavior correct?

The reason why these are my main concerns, is because this defines the feature itself, and fixing in future might not offer backwards compatibility.

Please, tell me what you think. I tried to blend in as much as possible, also trying to add the minimum amount of new code as possible. And of course, feel free to deny this feature. I would just like to know the reason, in this case.