The Importance of the Async Pipe
We have spent a lot of time talking about subscribing to observables, and even pointing out how an observable stream won’t actually even do anything until you subscribe to it. Given that, the advice I am going to give you in this lesson might seem a little odd:
Avoid subscribing as much as possible!
Perhaps I should phrase that as avoid subscribing as much as practical. We do still need to subscribe to observables in order to get them to do anything, but wherever possible we are going to use the async
pipe to do the subscribing for us.
We have seen this a little already:
@Component({
selector: 'app-home',
template: `
<app-greeting [name]="name$ | async"></app-greeting>
`
})
export class HomeComponent {
name$ = of('Josh')
}
We can use it to pull values out of streams and pass them into inputs as above. We can also use it render out values directly in the template:
@Component({
selector: 'app-home',
template: `
<h2 *ngIf="name$ | async as name">{{ name }}</h2>
`
})
export class HomeComponent {
name$ = of('Josh')
}
Or, as we have seen recently, we can take this a little further and create a single view model vm$
stream that contains all of the data from streams for our entire template:
@Component({
selector: 'app-home',
template: `
<ng-container *ngIf="vm$ | async as vm">
<p>{{ vm.name }}</p>
<p>{{ vm.luckyNumber }}</p>
<p>{{ vm.attempt }}</p>
</ng-container>
`
})
export class HomeComponent {
name$ = of('Josh');
luckyNumber$ = from([5, 22, 587]);
attempts$ = new BehaviorSubject(0);
vm$ = combineLatest([name$, luckyNumber$, attempts$]).pipe(
map(([name, luckyNumber, attempt]) => ({name, luckyNumber, attempt}))
)
}
An important part about the *ngIf
syntax above is that this section of the template won’t render until the stream emits and our vm
object is actually available to use. Later we will see more advanced examples where we display an alternative loading template if the stream has not emitted yet.
There are three main reasons for using the | async
pipe, and we will talk about each separately:
- The
async
pipe handles automatically subscribing and unsubscribing for you - Once we
subscribe
to a stream we are no longer coding “reactively”. Using theasync
pipe encourages us to keep data in streams until they reach their final destination (the template) - When a new value is emitted using the
async
pipe it will trigger change detection, which is important forOnPush
change detection
Let’s focus on these points in a little more detail.
The Importance of Unsubscribing
As we have seen, observables can emit multiple values over time. They will just keep emitting these values, and triggering the next
handler of the observer, until: