3d cartoon hands holding a phone

Unlock full course by purchasing a membership

Lesson 6

The Importance of the Async Pipe

Subscribing safely in the template

STANDARD

The Importance of the Async Pipe

IMPORTANT: This lesson is still important for understanding Angular applications that do not use signals. However, in applications that do use signals there isn’t really any reason to use the async pipe. Instead, you would just convert your observable stream to a signal using toSignal instead — this achieves practically the same goal as using the async, but has less “gotchas” in terms of accidentally triggering unintended subscriptions. Many of the motivations of using the async pipe still overlap with the idea of using toSignal — the overall goal is still to keep your data in a reactive mechanism until it reaches it’s destination.

The rest of this lesson will assume that the application is not using signals. However, as you will see in the example applications we will be building soon, we will not use the async pipe. There are many references to OnPush change detection in this lesson which we will also not be using in an application that uses signals.

We have seen a little of the async pipe already in examples like this:

@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, 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.

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 the async 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 for OnPush 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:

  • It is unsubscribed
  • It errors
  • It triggers the complete notifier

Some observables might just emit one value, some might emit multiple then complete, some might emit values forever and never complete.

This creates the perfect situation for memory leaks. It creates the potential for subscribing to an observable that keeps emitting values over time and not unsubscribing from that without realising that it is still emitting values and doing things. Then maybe the user navigates to the component creating the subscription again, and again, and again, and so on.

STANDARD
Key

Thanks for checking out the preview of this lesson!

You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).