Skip to content

Commit

Permalink
fix(docs-infra): convert hard-coded comparing-observables examples …
Browse files Browse the repository at this point in the history
…into a proper mini-app

Previously, the examples in the `comparing-observables` guide were hard-coded.
This made it impossible to test them and verify they are correct.

This commit fixes this by converting them into a proper mini-app. In a
subsequent commit, tests will be added to verify that the source code
works as expected (and guard against regressions).

Fixes #31024
  • Loading branch information
sonukapoor committed Dec 16, 2019
1 parent ad98702 commit 24a7a71
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 49 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Expand Up @@ -867,6 +867,7 @@ testing/** @angular/fw-test
/aio/content/guide/observables.md @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/observables/** @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/comparing-observables.md @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/comparing-observables/** @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/observables-in-angular.md @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/observables-in-angular/** @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/practical-observable-usage.md @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
Expand Down
40 changes: 40 additions & 0 deletions aio/content/examples/comparing-observables/src/observables.ts
@@ -0,0 +1,40 @@
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';

// #docregion observable

// declare a publishing operation
const observable = new Observable<number>(observer => {
// Subscriber fn...
});

// initiate execution
observable.subscribe(() => {
// observer handles notifications
});

// #enddocregion observable

// #docregion unsubscribe

const subscription = observable.subscribe(() => {
// observer handles notifications
});

subscription.unsubscribe();

// #enddocregion unsubscribe

// #docregion error

observable.subscribe(() => {
throw Error('my error');
});

// #enddocregion error

// #docregion chain

observable.pipe(map(v => 2 * v));

// #enddocregion chain
25 changes: 25 additions & 0 deletions aio/content/examples/comparing-observables/src/promises.ts
@@ -0,0 +1,25 @@
// #docregion promise
// initiate execution
const promise = new Promise<number>((resolve, reject) => {
// Executer fn...
});

promise.then(value => {
// handle result here
});

// #enddocregion promise

// #docregion chain

promise.then(v => 2 * v);

// #enddocregion chain

// #docregion error

promise.then(() => {
throw Error('my error');
});

// #enddocregion error
100 changes: 51 additions & 49 deletions aio/content/guide/comparing-observables.md
Expand Up @@ -21,68 +21,67 @@ Observables are often compared to promises. Here are some key differences:

* Observables are not executed until a consumer subscribes. The `subscribe()` executes the defined behavior once, and it can be called again. Each subscription has its own computation. Resubscription causes recomputation of values.

<code-example hideCopy>
// declare a publishing operation
new Observable((observer) => { subscriber_fn });
// initiate execution
observable.subscribe(() => {
// observer handles notifications
});
</code-example>
<code-example
path="comparing-observables/src/observables.ts"
header="src/observables.ts (observable)"
region="observable">
</code-example>

* Promises execute immediately, and just once. The computation of the result is initiated when the promise is created. There is no way to restart work. All `then` clauses (subscriptions) share the same computation.

<code-example hideCopy>
// initiate execution
new Promise((resolve, reject) => { executer_fn });
// handle return value
promise.then((value) => {
// handle result here
});
</code-example>
<code-example
path="comparing-observables/src/promises.ts"
header="src/promises.ts (promise)"
region="promise">
</code-example>

### Chaining

* Observables differentiate between transformation function such as a map and subscription. Only subscription activates the subscriber function to start computing the values.


<code-example hideCopy>observable.pipe(map((v) => 2*v));</code-example>

<code-example
path="comparing-observables/src/observables.ts"
header="src/observables.ts (chain)"
region="chain">
</code-example>

* Promises do not differentiate between the last `.then` clauses (equivalent to subscription) and intermediate `.then` clauses (equivalent to map).


<code-example hideCopy>promise.then((v) => 2*v);</code-example>

<code-example
path="comparing-observables/src/promises.ts"
header="src/promises.ts (chain)"
region="chain">
</code-example>

### Cancellation

* Observable subscriptions are cancellable. Unsubscribing removes the listener from receiving further values, and notifies the subscriber function to cancel work.

<code-example hideCopy>
const sub = obs.subscribe(...);
sub.unsubscribe();
</code-example>
<code-example
path="comparing-observables/src/observables.ts"
header="src/observables.ts (unsubcribe)"
region="unsubscribe">
</code-example>

* Promises are not cancellable.

### Error handling

* Observable execution errors are delivered to the subscriber's error handler, and the subscriber automatically unsubscribes from the observable.

<code-example hideCopy>
obs.subscribe(() => {
throw Error('my error');
});
</code-example>
<code-example
path="comparing-observables/src/observables.ts"
header="src/observables.ts (error)"
region="error">
</code-example>

* Promises push errors to the child promises.

<code-example hideCopy>
promise.then(() => {
throw Error('my error');
});
</code-example>
<code-example
path="comparing-observables/src/promises.ts"
header="src/promises.ts (error)"
region="error">
</code-example>

### Cheat sheet

Expand All @@ -100,14 +99,16 @@ The following code snippets illustrate how the same kind of operation is defined
<tr>
<td>Creation</td>
<td>
<pre>new Observable((observer) => {
observer.next(123);
});</pre>
<pre>
new Observable((observer) => {
observer.next(123);
});</pre>
</td>
<td>
<pre>new Promise((resolve, reject) => {
resolve(123);
});</pre>
<pre>
new Promise((resolve, reject) => {
resolve(123);
});</pre>
</td>
</tr>
<tr>
Expand All @@ -118,14 +119,16 @@ The following code snippets illustrate how the same kind of operation is defined
<tr>
<td>Subscribe</td>
<td>
<pre>sub = obs.subscribe((value) => {
console.log(value)
});</pre>
<pre>
sub = obs.subscribe((value) => {
console.log(value)
});</pre>
</td>
<td>
<pre>promise.then((value) => {
console.log(value);
});</pre>
<pre>
promise.then((value) => {
console.log(value);
});</pre>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -165,7 +168,6 @@ subscription.unsubscribe();</pre>
<pre>function handler(e) {
console.log(‘Clicked’, e);
}

// Setup & begin listening
button.addEventListener(‘click’, handler);
// Stop listening
Expand Down

0 comments on commit 24a7a71

Please sign in to comment.