角度2+中的内置异步管道为我们提供了一个很好的工具来轻松管理可观察到的订阅。有了它,我们可以学习在大多数情况下避免手动订阅组件类中的可观测对象。
比方说,我们想要有一个能给出当前每秒时间的可观测对象。在不使用异步管道的情况下,我们可能会这样做:
1import { Component, OnInit, OnDestroy } from '@angular/core';
2
3import { Observable } from 'rxjs/Observable';
4import { Subscription } from 'rxjs/Subscription';
5import 'rxjs/add/observable/interval';
6import 'rxjs/add/operator/map';
7
8@Component({
9 selector: 'app-root',
10 template: `Time: {{ time | date:'mediumTime' }}`
11})
12export class AppComponent implements OnInit, OnDestroy {
13 time: Date;
14 timeSub: Subscription;
15
16 ngOnInit() {
17 this.timeSub = Observable
18 .interval(1000)
19 .map(val => new Date())
20 .subscribe(val => this.time = val);
21 }
22
23 ngOnDestroy() {
24 this.timeSub.unsubscribe();
25 }
26}
在我们的OnInit钩子中,我们创建了一个observable,它每秒发出一个值,并将该值映射到一个新的日期。然后,我们订阅了这个observable,并将我们的time类变量设置为发出的值。我们还确保在组件被销毁时取消订阅观察对象,以便在我们自己之后进行清理。
在模板中,我们使用内置的日期管道将日期转换为所需的分钟和秒格式。
然而,这是相当多的样板代码,如果我们忘记取消订阅,就会面临造成内存泄漏的风险。我们可以大大简化,以下是使用异步管道实现的相同功能:
1import { Component } from '@angular/core';
2
3import { Observable } from 'rxjs/Observable';
4import 'rxjs/add/observable/interval';
5import 'rxjs/add/operator/map';
6
7@Component({
8 selector: 'app-root',
9 template: `Time: {{ time$ | async | date:'mediumTime' }}`
10})
11export class AppComponent {
12 time$ = Observable
13 .interval(1000)
14 .map(val => new Date());
15}
P2C管道负责订阅和解包数据,以及在组件被销毁时取消订阅。
我们还可以使用异步管道来展开数据并将数据传递给子组件的输入:
1[label app.component.html]
2<app-child [time]="time$ | async"></app-child>
孩子现在真的没什么可做的,除了显示数据。
带ngFor的异步管道
假设我们有一个稍微复杂一点的数据结构可用作可观察对象,并且在获得其值(模拟网络请求)之前设置了1秒的人工延迟:
1import { Component } from '@angular/core';
2
3import { Observable } from 'rxjs/Observable';
4import 'rxjs/add/observable/of';
5import 'rxjs/add/operator/map';
6import 'rxjs/add/operator/delay';
7
8@Component({ ... })
9export class AppComponent {
10 cities$ = Observable
11 .of([
12 {name: 'Los Angeles', population: '3.9 million', elevation: '233′'},
13 {name: 'New York', population: '8,4 million', elevation: '33′'},
14 {name: 'Chicago', population: '2.7 million', elevation: '594′'},
15 ])
16 .delay(1000);
17}
在模板中,我们可以在数据到达时使用如下ngFor指令进行解包和订阅:
1<ul>
2 <li *ngFor="let city of cities$ | async">
3 Name: {{ city.name }},
4 Population: {{ city.population }},
5 Elevation: {{ city.elevation }}</li>
6</ul>
带ngIf的异步管道
下面是一个使用ngif结构指令的示例。我们的观察点如下所示:
1word$ = Observable.of('Abibliophobia');
我们的模板如下所示:
1<span *ngIf="(word$ | async)?.length > 9; else shortWord">
2 Long word: {{ word$.value }}
3</span>
4
5<ng-template #shortWord>
6 Short word: {{ word$.value }}
7</ng-template>
我们会得到:
1Long word: Abibliophobia
请注意,我们如何通过异步管道传递单词$ obable,但将其括在圆括号中,以便能够检查展开值上的长度。我们还利用了Elvis算子(?)以避免在Word$的值尚不可用时出现错误。