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
import { Pipe, PipeTransform } from '@angular/core';
import { Http } from '@angular/http';
import './rxjs-extensions';
// #docregion pipe-metadata
@Pipe({
@ -9,20 +10,20 @@ import { Http } from '@angular/http';
})
// #enddocregion pipe-metadata
export class FetchJsonPipe implements PipeTransform {
private fetchedJson: any = null;
private prevUrl = '';
private cachedData: any = null;
private cachedUrl = '';
constructor(private _http: Http) { }
constructor(private http: Http) { }
transform(url: string): any {
if (url !== this.prevUrl) {
this.prevUrl = url;
this.fetchedJson = null;
this._http.get(url)
if (url !== this.cachedUrl) {
this.cachedData = null;
this.cachedUrl = url;
this.http.get(url)
.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
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { Observable } from 'rxjs/Observable';
import './rxjs-extensions';
@Component({
selector: 'hero-message',

View File

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

View File

@ -1,6 +1,5 @@
// #docregion
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import 'rxjs/Rx';
import { AppModule } from './app.module';
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,
it doesn't extract the resolved values and expose them for binding,
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
Let's write one more impure pipe, a pipe that makes an HTTP request to the server.
Normally, that's a horrible idea.
It's probably a horrible idea no matter what we do.
We're forging ahead anyway to make a point.
Remember that impure pipes are called every few microseconds.
Let's write one more impure pipe, a pipe that makes an HTTP request.
Remember that impure pipes are called every few milliseconds.
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.
It caches the request URL and waits for a result which it also caches when it arrives.
The pipe returns the cached result (which is null while a request is in flight)
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:
We are careful.
The pipe only calls the server when the request URL changes and it caches the server response.
Here's the code, which uses the [Angular http](server-communication.html) client to retrieve data:
+makeExample('pipes/ts/app/fetch-json.pipe.ts', null, 'app/fetch-json.pipe.ts')
:marked
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)')
: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.
Then we demonstrate it in a harness component whose template defines two bindings to this pipe,
both requesting the heroes from the `heroes.json` file.
+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
:marked
The component renders like this:
figure.image-display
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
### *JsonPipe*
The second binding involving the `FetchPipe` uses more pipe chaining.
We take the same fetched results displayed in the first binding
and display them again, this time in JSON format by chaining through to the built-in `JsonPipe`.
The second `fetch` pipe binding above demonstrates more pipe chaining.
It displays the same hero data in JSON format by chaining through to the built-in `JsonPipe`.
.callout.is-helpful
header Debugging with the json pipe
@ -406,12 +404,7 @@ figure.image-display
The [JsonPipe](../api/common/index/JsonPipe-pipe.html)
provides an easy way to diagnosis a mysteriously failing data binding or
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")
:marked
### Pure pipes and pure functions

View File

@ -365,40 +365,38 @@ h3#async-pipe The impure #[i AsyncPipe]
### An impure caching pipe
Let's write one more impure pipe, a pipe that makes an HTTP request to the server.
Normally, that's a horrible idea.
It's probably a horrible idea no matter what we do.
We're forging ahead anyway to make a point.
Remember that impure pipes are called every few microseconds.
Let's write one more impure pipe, a pipe that makes an HTTP request.
Remember that impure pipes are called every few milliseconds.
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.
It caches the request URL and waits for a result which it also caches when it arrives.
The pipe returns the cached result (which is null while a request is in flight)
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:
We are careful.
The pipe only calls the server when the request URL changes and it caches the server response.
Here's the code, which uses the [Angular http](server-communication.html) client to retrieve data:
+makeExample('pipes/ts/app/fetch-json.pipe.ts', null, 'app/fetch-json.pipe.ts')
:marked
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)')
: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.
Then we demonstrate it in a harness component whose template defines two bindings to this pipe,
both requesting the heroes from the `heroes.json` file.
+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
:marked
The component renders like this:
figure.image-display
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
### *JsonPipe*
The second binding involving the `FetchPipe` uses more pipe chaining.
We take the same fetched results displayed in the first binding
and display them again, this time in JSON format by chaining through to the built-in `JsonPipe`.
The second `fetch` pipe binding above demonstrates more pipe chaining.
It displays the same hero data in JSON format by chaining through to the built-in `JsonPipe`.
.callout.is-helpful
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
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")
:marked
### Pure pipes and pure functions