docs(pipes): improve FetchJsonPipe discussion (#2923)

This commit is contained in:
Ward Bell 2016-12-02 14:22:41 -08:00 committed by GitHub
parent 977492a290
commit 93c78dae10
7 changed files with 57 additions and 68 deletions

View File

@ -1,6 +1,7 @@
// #docregion // #docregion
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
import { Http } from '@angular/http'; import { Http } from '@angular/http';
import './rxjs-extensions';
// #docregion pipe-metadata // #docregion pipe-metadata
@Pipe({ @Pipe({
@ -9,20 +10,20 @@ import { Http } from '@angular/http';
}) })
// #enddocregion pipe-metadata // #enddocregion pipe-metadata
export class FetchJsonPipe implements PipeTransform { export class FetchJsonPipe implements PipeTransform {
private fetchedJson: any = null; private cachedData: any = null;
private prevUrl = ''; private cachedUrl = '';
constructor(private _http: Http) { } constructor(private http: Http) { }
transform(url: string): any { transform(url: string): any {
if (url !== this.prevUrl) { if (url !== this.cachedUrl) {
this.prevUrl = url; this.cachedData = null;
this.fetchedJson = null; this.cachedUrl = url;
this._http.get(url) this.http.get(url)
.map( result => result.json() ) .map( result => result.json() )
.subscribe( result => this.fetchedJson = result ); .subscribe( result => this.cachedData = result );
} }
return this.fetchedJson; return this.cachedData;
} }
} }

View File

@ -1,6 +1,7 @@
// #docregion // #docregion
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Observable';
import './rxjs-extensions';
@Component({ @Component({
selector: 'hero-message', selector: 'hero-message',

View File

@ -3,7 +3,6 @@ import { Component } from '@angular/core';
@Component({ @Component({
selector: 'hero-list', selector: 'hero-list',
// #docregion template
template: ` template: `
<h2>Heroes from JSON File</h2> <h2>Heroes from JSON File</h2>
@ -12,9 +11,7 @@ import { Component } from '@angular/core';
</div> </div>
<p>Heroes as JSON: <p>Heroes as JSON:
{{'heroes.json' | fetch | json}} {{'heroes.json' | fetch | json}}
</p> </p>`
`
// #enddocregion template
}) })
export class HeroListComponent { } export class HeroListComponent { }

View File

@ -1,6 +1,5 @@
// #docregion // #docregion
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import 'rxjs/Rx';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule); platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -0,0 +1,5 @@
// Extensions to RxJS used in this app.
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';

View File

@ -361,44 +361,42 @@ h3#async-pipe The impure #[i AsyncPipe]
The component doesn't have to subscribe to the async data source, The component doesn't have to subscribe to the async data source,
it doesn't extract the resolved values and expose them for binding, it doesn't extract the resolved values and expose them for binding,
and the component doesn't have to unsubscribe when it is destroyed and the component doesn't have to unsubscribe when it is destroyed
(a potent source of memory leaks). (a potential source of memory leaks).
### An impure caching pipe ### An impure caching pipe
Let's write one more impure pipe, a pipe that makes an HTTP request to the server. Let's write one more impure pipe, a pipe that makes an HTTP request.
Normally, that's a horrible idea.
It's probably a horrible idea no matter what we do. Remember that impure pipes are called every few milliseconds.
We're forging ahead anyway to make a point.
Remember that impure pipes are called every few microseconds.
If we're not careful, this pipe will punish the server with requests. If we're not careful, this pipe will punish the server with requests.
We are careful. Our pipe only makes a server call if the request URL has changed. We are careful.
It caches the request URL and waits for a result which it also caches when it arrives. The pipe only calls the server when the request URL changes and it caches the server response.
The pipe returns the cached result (which is null while a request is in flight) Here's the code, which uses the [Angular http](server-communication.html) client to retrieve data:
after every Angular call and only contacts the server as necessary.
Here's the code, which uses the [Angular http](server-communication.html) facility
to retrieve a `heroes.json` file:
+makeExample('pipes/ts/app/fetch-json.pipe.ts', null, 'app/fetch-json.pipe.ts') +makeExample('pipes/ts/app/fetch-json.pipe.ts', null, 'app/fetch-json.pipe.ts')
:marked :marked
Then we demonstrate it in a harness component whose template defines two bindings to this pipe. Then we demonstrate it in a harness component whose template defines two bindings to this pipe,
+makeExample('pipes/ts/app/hero-list.component.ts', 'template', 'app/hero-list.component.ts (template)') both requesting the heroes from the `heroes.json` file.
:marked
Despite the two bindings and what we know to be frequent pipe calls,
the nework tab in the browser developer tools confirms that there is only one request for the file.
+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
:marked
The component renders like this: The component renders like this:
figure.image-display figure.image-display
img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List") img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List")
:marked
A breakpoint on the pipe's request for data shows that
* each binding gets its own pipe instance
* each pipe instance caches its own url and data
* each pipe instance only calls the server once
:marked :marked
### *JsonPipe* ### *JsonPipe*
The second binding involving the `FetchPipe` uses more pipe chaining. The second `fetch` pipe binding above demonstrates more pipe chaining.
We take the same fetched results displayed in the first binding It displays the same hero data in JSON format by chaining through to the built-in `JsonPipe`.
and display them again, this time in JSON format by chaining through to the built-in `JsonPipe`.
.callout.is-helpful .callout.is-helpful
header Debugging with the json pipe header Debugging with the json pipe
@ -407,11 +405,6 @@ figure.image-display
provides an easy way to diagnosis a mysteriously failing data binding or provides an easy way to diagnosis a mysteriously failing data binding or
inspect an object for future binding. inspect an object for future binding.
:marked
Here's the complete component implementation:
+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
a(id="pure-pipe-pure-fn") a(id="pure-pipe-pure-fn")
:marked :marked
### Pure pipes and pure functions ### Pure pipes and pure functions

View File

@ -365,40 +365,38 @@ h3#async-pipe The impure #[i AsyncPipe]
### An impure caching pipe ### An impure caching pipe
Let's write one more impure pipe, a pipe that makes an HTTP request to the server. Let's write one more impure pipe, a pipe that makes an HTTP request.
Normally, that's a horrible idea.
It's probably a horrible idea no matter what we do. Remember that impure pipes are called every few milliseconds.
We're forging ahead anyway to make a point.
Remember that impure pipes are called every few microseconds.
If we're not careful, this pipe will punish the server with requests. If we're not careful, this pipe will punish the server with requests.
We are careful. Our pipe only makes a server call if the request URL has changed. We are careful.
It caches the request URL and waits for a result which it also caches when it arrives. The pipe only calls the server when the request URL changes and it caches the server response.
The pipe returns the cached result (which is null while a request is in flight) Here's the code, which uses the [Angular http](server-communication.html) client to retrieve data:
after every Angular call and only contacts the server as necessary.
Here's the code, which uses the [Angular http](server-communication.html) facility
to retrieve a `heroes.json` file:
+makeExample('pipes/ts/app/fetch-json.pipe.ts', null, 'app/fetch-json.pipe.ts') +makeExample('pipes/ts/app/fetch-json.pipe.ts', null, 'app/fetch-json.pipe.ts')
:marked :marked
Then we demonstrate it in a harness component whose template defines two bindings to this pipe. Then we demonstrate it in a harness component whose template defines two bindings to this pipe,
+makeExample('pipes/ts/app/hero-list.component.ts', 'template', 'app/hero-list.component.ts (template)') both requesting the heroes from the `heroes.json` file.
:marked
Despite the two bindings and what we know to be frequent pipe calls,
the nework tab in the browser developer tools confirms that there is only one request for the file.
+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
:marked
The component renders like this: The component renders like this:
figure.image-display figure.image-display
img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List") img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List")
:marked
A breakpoint on the pipe's request for data shows that
* each binding gets its own pipe instance
* each pipe instance caches its own url and data
* each pipe instance only calls the server once
:marked :marked
### *JsonPipe* ### *JsonPipe*
The second binding involving the `FetchPipe` uses more pipe chaining. The second `fetch` pipe binding above demonstrates more pipe chaining.
We take the same fetched results displayed in the first binding It displays the same hero data in JSON format by chaining through to the built-in `JsonPipe`.
and display them again, this time in JSON format by chaining through to the built-in `JsonPipe`.
.callout.is-helpful .callout.is-helpful
header Debugging with the json pipe header Debugging with the json pipe
@ -407,11 +405,6 @@ figure.image-display
provides an easy way to diagnosis a mysteriously failing data binding or provides an easy way to diagnosis a mysteriously failing data binding or
inspect an object for future binding. inspect an object for future binding.
:marked
Here's the complete component implementation:
+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
a(id="pure-pipe-pure-fn") a(id="pure-pipe-pure-fn")
:marked :marked
### Pure pipes and pure functions ### Pure pipes and pure functions