-
Notifications
You must be signed in to change notification settings - Fork 26.2k
feat(docs): add Observable and Rx docs #21423
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
}); | ||
chaining | ||
observable.map((v) => 2*v); | ||
Observables differentiate between transformation function such as a map and subscription. Only subscription activase the subscribe Function to start computing the values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo activase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
Angular provides an EventEmitter class that’s used when publishing values from a Component through the `@Output()` decorator. Angular’s EventEmitter class extends from Observable, but adds a method `emit()` so it can send arbitrary values. Calling the `emit()` function will cause any subscribed Observers’ `next()` method to be called with the same value. | ||
|
||
The example on the [EventEmitter0(https://angular.io/api/core/EventEmitter)] docs page is a good example of it’s usage: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo EventEmitter0
(and the link reference is broken)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
aio/content/guide/observables.md
Outdated
|
||
Use the Observable constructor to create an Observable stream of any type. The constructor takes as its argument a Subscriber function to run when the Observable’s `subscribe()` method executes. A subscriber function receives an Observer, and can publish values to the Observer's `next()` method. | ||
|
||
For example, to create an Observable equivalent to the `Observable.of(1, 2, 3)` above, you could so something like this: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
## Exponential backoff | ||
|
||
Exponential backoff is a technique where you retry an API after failure, making the time in between retries longer after each consecutive failure, with a maximum number of retries after which the request is considered to have failed. This can be quite complex to implement with Promises and other methods of tracking AJAX calls, but with Observables it is very easy: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
double space between ... to have failed. This can be ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
To illustrate how and when to unsubscribe, consider a component named `HeroCounterComponent` that performs the simple task of increasing a total of heroes. The counter runs as long as the component is active in the view. Once the component is destroyed, you no longer want to listen for any changes coming from the Observable counter, so you can use the ngOnDestroy lifecycle hook to unsubscribe from the Observable counter and clean up its resources. | ||
|
||
Disposing of a single subscription when your component is destroyed is very manageable, but as you use more Observables, managing multiple subscriptions can get unwieldy. One way to manage them is to use operators that cause a stream to complete, which in turn causes the unsubscription logic to run. For example, the `takeUntil` operator listens for one or more supplied Observables to complete, then notifies the source Observable to complete. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
double space between ...can get unwieldy. One way to...
And in For example, the takeUntil operator listens
part
|
||
Disposing of a single subscription when your component is destroyed is very manageable, but as you use more Observables, managing multiple subscriptions can get unwieldy. One way to manage them is to use operators that cause a stream to complete, which in turn causes the unsubscription logic to run. For example, the `takeUntil` operator listens for one or more supplied Observables to complete, then notifies the source Observable to complete. | ||
|
||
A typical Observable creates a new, independent execution for each subscribed observer. To illustrate managing a number of subscriptions, we can create a _multicasting_ Observable that keeps a list of subscribers, and broadcasts its values to all of them. Then we can update the hero counter example to use the `takeUntil` operator to manage multiple subscribers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
double space between Then we can update
|
||
A typical Observable creates a new, independent execution for each subscribed observer. To illustrate managing a number of subscriptions, we can create a _multicasting_ Observable that keeps a list of subscribers, and broadcasts its values to all of them. Then we can update the hero counter example to use the `takeUntil` operator to manage multiple subscribers. | ||
|
||
> NOTE: RxJS defines a multicasting Observable called a Subject, which keeps a list of registered observers, and notifies all observers each time a new value is emitted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
double space between Observable called a Subject,
|
||
When the `onDestroy` Observable completes, the counter Observable also completes and stops producing values. This approach scales up, allowing a single Observable to trigger completion across multiple subscriptions. | ||
|
||
** CODE SAMPLE NEEDED. EXAMPLE [HERE](https://gist.github.com/alxhub/4c55e39b572c4cdcbb369fb3598cc92c).** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this intentional or the code sample should be reported?
There are a lot more ** EXAMPLE HERE ** comments in the doc, so this intentional probably, sorry for reporting that
|
||
As with other services, you'll import the `EventAggregatorService` and MessageLogComponent and add it to the AppModule providers and declarations arrays respectively. | ||
|
||
To see your message bus in action, you'll import and inject the `EventAggregatorService` in the AppComponent and add an event when the Application starts and add the message-log component to the AppComponenttemplate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AppComponenttemplate
not fully PascalCase
|
||
# Testing Observable Services | ||
|
||
First, let's look at the sharing data with a stream example. You want to verify the functionality of the service including its initial state, and that new entries are added into the stream each time the add method is used. If you're familiar with Angular's TestBed, this is a normal setup. You use the TestBed to setup the configure a testing module include the necessary providers, and use the TestBed.get() method to get a new instance of the EventAggregatorService before each test run. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You use the TestBed to setup the configure a testing module include the necessary providers
is this sentence correct?
4099e47
to
97f0ce4
Compare
You can preview 97f0ce4 at https://pr21423-97f0ce4.ngbuilds.io/. |
97f0ce4
to
fb88455
Compare
You can preview fb88455 at https://pr21423-fb88455.ngbuilds.io/. |
aio/content/guide/observables.md
Outdated
|
||
A handler for receiving Observable notifications implements the Observer interface. It is an object that defines callback methods to handle the three types of notifications that an Observable can send: | ||
|
||
| Notification Types | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting needs to be fixed on this table.
|
||
Observables are often compared to Promises. They both deliver values asynchronously, so what’s the difference? Unlike Promise, Observable delivers many values over time and is cancellable. Some of the other differences are described in the following table. | ||
|
||
<table> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These tables format nicely on Github, but not on Angular.io. Need to adjust the formatting so they display correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Observables do not deliver values asynchronously. In fact, they can but they often do not and that's pretty darned important.
IMO, relating Observables to Promises only leads to confusion. They're completely different things: like a screwdriver and a hammer. You can get a screw into a piece of wood with both (handle one-time async events), but that's about as similar as they get.
Hello? Don't want to hassle you. Sure you're busy. But this PR has some merge conflicts that you probably ought to resolve. |
fb88455
to
0412f81
Compare
You can preview 0412f81 at https://pr21423-0412f81.ngbuilds.io/. |
aio/content/guide/observables.md
Outdated
| error | Optional. A handler for an error notification. An error halts execution of the Observable instance. | | ||
| complete | Optional. A handler for the execution-complete notification. Delayed values can continue to be delivered to the next handler after execution is complete. | | ||
|
||
An observer object can define any combination of these handlers. If you don't supply a handler for a notification type, the observer ignores notifications of that type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a quick example pseudo code would be useful here.
Also should you say something along the lines of: Most of the time one does not need to create observables one only subscribes to them or uses composition methods to compose observables?
aio/content/guide/observables.md
Outdated
|
||
## Subscribing | ||
|
||
An Observable object begins publishing values only when someone subscribes to it. You subscribe by calling the subscribe() method of an Observable instance, passing an Observer to receive the notifications. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should Observer
be in back ticks since it is a type?
aio/content/guide/observables.md
Outdated
|
||
An Observable object begins publishing values only when someone subscribes to it. You subscribe by calling the subscribe() method of an Observable instance, passing an Observer to receive the notifications. | ||
|
||
> In order to show how subscribing works, we need to create a new Observable. There is an Observable constructor that you use to create customized Observable instances, but for illustration, we can use some static methods on the Observable class that create simple Observables of frequently used types: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Observable
in back ticks
aio/content/guide/rx-library.md
Outdated
### Observable from a Promise | ||
|
||
``` | ||
import { fromPromise } from 'rxjs/observable/fromPromise; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing'
before ;
aio/content/guide/rx-library.md
Outdated
### Observable from a Counter | ||
|
||
``` | ||
// Observable that will publish a value on an interval |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably should add imporf for interval
@@ -0,0 +1,38 @@ | |||
# Common Operators | |||
|
|||
RxJS provides many operators (over 150 of them!), but only a handful are used frequently. Here is a list of common operators with simple examples to show their usage. These examples are largely derived from the [RxJS 5 Operators By Example](https://github.com/btroncone/learn-rxjs/blob/master/operators/complete.md) page: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Text says that there are examples, but no examples are listed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
``` | ||
|
||
## Managing Subscriptions | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the plan with TBD here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed for MVP of the docs
@@ -0,0 +1,3 @@ | |||
# Testing | |||
|
|||
TBD. Original content [here](https://docs.google.com/document/d/1gGP5sqWNCHAWWV_GLdZQ1XyMO4K-CHksUxux0BFtVxk/edit#heading=h.ohqykkhzdhb2). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBD?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed for MVP of the docs. Will work in some of the testing guide from previous PR.
<tr> | ||
<td>Configuration</td> | ||
<td> | ||
<pre>fromEvent(inputEl, ‘keydown).pipe( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing trailing back tick on keydown
<p>Configured to listen for keystrokes, but provide a stream representing the value in the input.</p> | ||
</td> | ||
<td> | ||
<pre>element.addEventListener(eventName, (event) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eventName
should be 'keydown'
for consistency
@jasonaden FYI ... PR #20697 update to Testing guide teaches techniques for testing observable APIs. Those techniques include an intro to marble testing. There may be a cross-ref opportunity once that PR lands. |
So there's good news and bad news. 👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there. 😕 The bad news is that it appears that one or more commits were authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request. Note to project maintainer: This is a terminal state, meaning the |
@jbogarthyde I added you as a reviewer. When you're happy with the doc content, please approve as a reviewer. Thx. |
These seem to be the answers to my questions above: Q1: Judy sent a slack saying the content looks good to her, so that's done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found a couple typos (missing or extra letters). Capitalization of all titles and headings should be sentence caps. Most of the rest are also minor suggestions for clarity or style at the sentence level. I didn't make any structural recommendations at this time. Comments that begin "Recommend:" are optional.
aio/content/guide/observables.md
Outdated
|
||
Observables provide support for passing messages between publishers and subscribers in your application. Observables offer significant benefits over other techniques for event handling, asynchronous programming, and handling multiple values. | ||
|
||
Observables are declarative — that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. The subscribed consumer then receives notifications until the function completes, or they unsubscribe. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No spaces around em-dashes. https://developers.google.com/style/dashes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
aio/content/guide/observables.md
Outdated
|
||
Observables provide support for passing messages between publishers and subscribers in your application. Observables offer significant benefits over other techniques for event handling, asynchronous programming, and handling multiple values. | ||
|
||
Observables are declarative — that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. The subscribed consumer then receives notifications until the function completes, or they unsubscribe. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mismatched subject-verb. Recommend: The subscribed consumers then receives notifications until the function completes, or until they unsubscribe.
aio/content/guide/observables.md
Outdated
|
||
Observables are declarative — that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. The subscribed consumer then receives notifications until the function completes, or they unsubscribe. | ||
|
||
An Observable can deliver multiple values of any type — literals, messages, or events, depending on the context. The API for receiving values is the same whether the values are delivered synchronously or asynchronously. Because setup and teardown logic are both handled by the Observable, your application code only needs to worry about subscribing to consume values, and when done, unsubscribing. Whether the stream was keystrokes, an HTTP response, or an interval timer, the interface for listening to values and stopping listening is the same. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Global:
- Why is Observable always capitalized? Seems like this should be a regular noun, lowercase.
- Doc is inconsistent: observer object, observer, Observer. I prefer observer or observer object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I see that RxJS capitalizes Observables. That's unfortunate, because it's just a thing like "car." It's not a specific trademarked thing (Toyota), nor is it a specific code construct that must be capitalized. I'm fine either way I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be Observer
where we are referring to it as interface. observer
or observer object
should be fine in other uses.
aio/content/guide/observables.md
Outdated
|
||
Sometimes, instead of starting an independent execution for each subscriber, you want each subscription to get the same values -- even if values have already started emitting. This might be the case with something like an Observable of clicks on the document object. You might not want to register multiple listeners on the document, but instead re-use the first listener and send values out to each subscriber. | ||
|
||
This is called “multicasting”. When creating an Observable you should determine how you want that Observable to be used and whether or not you want to multicast it’s values. Changing the Observable above to be multicasted could look something like this: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Above: "This is known as multicasting." Implies that multicasting is the act of broadcasting to a list of subscribers in a single execution.
Here: "This is called multicasting." Implies that multicasting is specifically re-using a listener to send values out to a set of subscribers.
Recommendation: Define "multicasting" once near the beginning. "Multicasting is...." Then clean up the second "This is multicasting" to fit. For example, "Multicasting is achieved by re-using a listener..."
aio/content/guide/observables.md
Outdated
|
||
Sometimes, instead of starting an independent execution for each subscriber, you want each subscription to get the same values -- even if values have already started emitting. This might be the case with something like an Observable of clicks on the document object. You might not want to register multiple listeners on the document, but instead re-use the first listener and send values out to each subscriber. | ||
|
||
This is called “multicasting”. When creating an Observable you should determine how you want that Observable to be used and whether or not you want to multicast it’s values. Changing the Observable above to be multicasted could look something like this: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace "it's values" with "its values"
aio/content/guide/observables.md
Outdated
|
||
## Multicasting | ||
|
||
One feature of Observables is they don’t do anything until a subscription happens. In the previous examples, you can see that no event handlers are wired up and no values delivered until you subscribe to the Observable. But what happens when there are two subscriptions? A typical Observable creates a new, independent execution for each subscribed observer. If you have an Observable that keeps a list of subscribers, it can broadcast its values to all of them. This is known as multicasting. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this what you're trying to emphasize? "A typical Observable creates a new, independent execution for each subscribed observer. When an observer subscribes, the Observable wires up an event handler and delivers values to that observer. When a second observer subscribes, the Observable then wires up a new event handler and delivers values to that second observer in a separate execution. Multicasting is the practice of broadcasting to a list of multiple subscribers in a single execution. It's awesome because..." [everyone gets same values at the same time, everyone gets same values, event handling is centralized, ???]
aio/content/guide/observables.md
Outdated
|
||
One feature of Observables is they don’t do anything until a subscription happens. In the previous examples, you can see that no event handlers are wired up and no values delivered until you subscribe to the Observable. But what happens when there are two subscriptions? A typical Observable creates a new, independent execution for each subscribed observer. If you have an Observable that keeps a list of subscribers, it can broadcast its values to all of them. This is known as multicasting. | ||
|
||
Let’s look at an example, similar to the one above that counts from 1 to 3. But in this example we’ll introduce a 1 second delay between each number being emitted: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better not to start sentence with "But."
"This example introduces a one-second delay after each number emitted."
aio/content/guide/rx-library.md
Outdated
|
||
Reactive programming is an asynchronous programming paradigm concerned with data streams and the propagation of change ([Wikipedia](https://en.wikipedia.org/wiki/Reactive_programming)). RxJS (Reactive Extensions for JavaScript) is a library for reactive programming using Observables that makes it easier to compose asynchronous or callback-based code ([RxJS Docs](http://reactivex.io/rxjs/)). | ||
|
||
RxJS provides an implementation of the Observable type, which is needed until Observable becomes part of the language and until browsers support it. But the most important parts of the library are utility functions for creating and working with Observables. These utility functions can be used for: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recommend simplifying: RxJS provides an implementation of the Observable type, which is needed until Observable becomes part of the JavaScript language and until browsers support it. The library also provides utility functions for creating and working with Observables.
|
||
## Exponential backoff | ||
|
||
Exponential backoff is a technique where you retry an API after failure, making the time in between retries longer after each consecutive failure, with a maximum number of retries after which the request is considered to have failed. This can be quite complex to implement with Promises and other methods of tracking AJAX calls. With Observables, it is very easy: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"...is a technique in which you..."
aio/content/guide/rx-library.md
Outdated
|
||
## Naming conventions for Observables | ||
|
||
Because Angular applications are mostly written in TypeScript, you will typically know when a variable is an Observable. While the Angular framework generally does not employ a naming convention for Observables, in online examples and applications, you will often see Observables named with a trailing “$” sign. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recommend not using "while" unless you mean time. Also can "generally does not employ" be simplified?
"Although the Angular framework does not enforce a naming convention for Observables, you will often see Observables named with a trailing dollar sign ("$")."
aio/content/guide/rx-library.md
Outdated
|
||
Operators are functions that build on the Observables foundation to enable sophisticated manipulation of collections. For example, RxJS defines operators for operations such as `map()`, `filter()`, `concat()`, and `flatMap()`. | ||
|
||
An operator takes configuration options, and returns another function which takes a source Observable. When executing this returned function, the operator observes the source Observable’s emitted values, transforms them, and returns a new Observable of those transformed values. Here is a simple example: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be a comma before which, but that creates some complex parsing.
"An operator takes configuration options, and it returns another function, which takes a source Observable."
"Operators take configuration options, and they return a function that takes a source Observable."
Thanks for creating the documentation, it looks great! I didn't see anything about unsubscribing from observables though. Did I miss it? |
21b2d4f
to
31ee194
Compare
@spottedmahn Good question. No, this doc doesn't immediately cover that. And we will have to follow up with another addition to the docs. Similarly with testing. I think it'll be good to get this doc out since it should be useful now, rather than waiting to add more content. I assigned your referenced issue to myself so I can grab it in an upcoming sprint. |
You can preview 31ee194 at https://pr21423-31ee194.ngbuilds.io/. |
Addressed comments. She is on vacation so hard to get approval.
You can preview 4f314f6 at https://pr21423-4f314f6.ngbuilds.io/. |
I'm here. :-) I took a quick look. Extra file and title caps are resolved. I didn't recheck every copy edit. LTGM. |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
This PR adds documentation to Angular.io for Observables and the basics of RxJS. The intention behind this documentation is to give an introduction to
Observable
as a type. It also introduces just enough Rx to work with an Angular application. For example, Rx Observable creation utilities and operators used through thepipe
function/method.This doc intentionally avoids more complex discussions such as higher order Observables (this may be added later), hot and cold Observables, marble diagrams, etc. For topics like these (and more), developers should see the RxJS documentation directly.
Some sections are currently incomplete: testing, common operators, and some of the Practical Usage page. Additionally, the examples need to be moved out so they are runnable.
Current preview available at https://pr21423-0412f81.ngbuilds.io/guide/observables