Understand and Utilize the Async Pipe in Angular 2

UPDATE: Check out the video version of this article, Using the Async Pipe in Angular 2, at Egghead.io!

With the release of Angular 2 Beta last month, the team declared the next generation of AngularJS ready for large applications. As a developer, the time is now to start acquiring an understanding of the new API, patterns, and features. One such exciting new feature is the async pipe, which allows the auto update of component templates through emitted observable events and resolved promises. This can not only provide a reduction in code but also assist in facilitating exciting new data flow and state management patterns and architecture, coupled with performance optimization. Furthermore, an understanding of how this feature was implemented can demystify the process and help inspire new ideas. Let’s dive in and learn how to put the new async pipe to use in our Angular 2 applications!

What Are Pipes In Angular 2?

All source code for this article can be found here.
So what are pipes in Angular 2? Simply put, pipes are classes implementing a single function interface, accepting an input value (supplied on the left in template) with an optional parameter array, returning a transformed value. If you are familiar with Angular 1 you can think of pipes as more flexible filters. Because each pipe must return a new value they can be chained, or composed, until the desired output is reached. The flow of inputs and outputs through pipes is demonstrated below:

Ng2-Pipe

Pipe data flow

To create your own pipe you need to decorate a basic class with the new @Pipe decorator and conform to the PipeTransform interface of transform(value:number, args:string[]) : any.

Enter the Async Pipe

One of the more original features I have come across in Angular 2 is the async pipe, a new addition to the more standard pipes (or filters) we saw in the first edition of Angular. This pipe accepts a promise or observable as input, updating the view with the appropriate value(s) when the promise is resolved or observable emits a new value. This can have a dual impact of reducing component-level code while also providing incredible performance optimization opportunities when utilized correctly.

Before we go any further, let’s start by looking at what our code might look like without the use of the async pipe. Below is an example of how we typically invoke an asynchronous function which returns a promise, ultimately assigning the result of that promise to a variable in our component, displayed in the template.

Similarly, with an observable, we subscribe to the stream, manually setting emitted values to a variable to be used in the component template.

While it is certainly fine to write code in this manner, introducing the async pipe allows us to turn the above code into the following variation.

As you can see, this eliminates the need to manually update component values based on the result of promises or new values being emitted by observable streams. While this reduction in boilerplate is helpful, the real benefit comes from a performance perspective. Before we dive into that, let’s first understand what is going on behind the scenes to make this work.

How does it work?

When utilizing a library it’s often helpful to not only understand the surface level API but also what’s going on behind the scenes to make it function. Not only can this remove some of the ‘magic’ from the consumed library but it can also teach important lessons and inspire ideas for your own future creations. Let’s walk through, step by step, the code behind the async pipe.
Small sections of the original source will be omitted for brevity sake. Click here. for the full source.

1.) Component Creation

When a new component is created and change detection is triggered, the async pipe transform method will be invoked, accepting the value on the left side of the pipe. For this example we will assume a basic observable utilizing an interval operator, configured to emit a new value once a second. This is not important, all observables are handled similarly.

As seen below, the first time transform is called the local _obj property will be null, causing the _subscribe function to be invoked.

2.) Select Subscription Strategy

The subscribe function determines whether the value passed is an observable or promise, selects the appropriate ‘strategy’, or method for handling future value(s), and creates the appropriate subscription. In this case we are supplying an observable, so the _observableStrategy will be returned.

3.) Create Subscription

Each strategy, observable or promise, features a createSubscription method to be invoked on the last line of the _subscribe method above. For observables, this method is passed our observable and the _updateLatestValue function to be added as the next, or success function when the observable is subscribed. This means each time a new value is successfully emitted from our observable stream the _updateLatestValue function will be called. This is the key to making the async pipe work. Promises are handled similarly except .then() is added with _updateLatestValue invoked upon a successful result.

4.) Change Detection / Transform

As we saw above, when a new value is emitted _latestValue is updated and change detection is set to fire. Upon this action, the transform method is also invoked, this time with a pre-existing subscription.

Because _latestValue was updated when a new value was emitted, this value no longer matches _latestReturnedValue in the transform method. The _latestReturnedValue variable will be reset to the new value, and the new value will be returned from the transform method to be displayed in our component template.

To recap:

  • The observable passed into the async pipe is subscribed to, with successfully emitted values invoking the _updateLastestValue method supplied from the AsyncPipe class.
  • This method sets a local property, _latestValue (initially null) to the newly emitted value then triggers Angular change detection to fire.
  • When transform is called, if this value does not match the previous value (_latestReturnedValue), the new value is returned and _latestReturnValue is updated, prepared for the next time transform is called.

Performance Benefits

The main benefit to utilizing the async pipe is not the reduction in code, but the performance optimization and data flow patterns that this feature can help enable. In Angular 2, through the ChangeDetectionStrategy @Component property, we are are able to supply the framework with information regarding how change detection for a component should be handled. In the words of core Angular team member Victor Savkin:

If a component depends only on its input properties, and they are observable, then this component can change if and only if one of its input properties emits an event. Therefore, we can skip the component’s subtree in the change detection tree until such an event occurs. When it happens, we can check the subtree once, and then disable it until the next change.

Assuming our application state is engineered correctly, we can effectively turn off change detection within our application until it is absolutely necessary. The performance implications this has over a standard, two way data-binding type approach are significant, as outlined in this article by Victor Savkin. At a templating level, handling changes as they occur is made painless by the addition of the async pipe.

Moving Forward

While reactive architecture ideas, patterns, and best practices in the context of an Angular 2 application are still in the early stages, there is a lot of momentum behind this movement. Rob Wormold recently released the ngrx library, heavily inspired by Dan Abramov’s Redux, which aims to tackle state management by taking full advantage of Angular 2’s deep RxJS integration. Wayne Maurer also released an excellent blog post detailing how to integrate the MVI (Model-View-Intent) architecture popularized by Andre Staltz and Cycle.js into an Angular 2 application. Expect more to be released on this subject in the coming weeks and months as Angular 2 nears official release.

There are also early plans for Angular 2 to include a simpler API for handling observables and view events, making the implementation of reactive architecture patterns even more intuitive. With RxJS integration already deeply engrained into Angular 2 core, this feels like a natural progression. This is an exciting space and the async pipe is a small but important piece to the puzzle.

Conclusion

As always, if you have any questions, comments, or suggestions for a future topic you would like covered, feel free to drop me a line below or on Twitter. I look forward to covering Angular 2 and RxJS extensively over the coming months as new patterns, best practices, and tooling emerge. The full source code for this article is available on Github if you would like a quick way to start experimenting on your own. If you are interested in the ngrx project, check out my repository aggregating examples and articles as well as my new egghead.io video, @ngrx/store in 10 minutes. Until next time, happy coding!

  • Lars Jeppesen

    Great article, thank you!

    • Btroncone

      Thanks for reading!

  • Nathan Walker

    Really good stuff, thanks for detailing all this!

    • Btroncone

      Glad you enjoyed, thanks for the comment!

  • Celine Kessler

    Hello, I have been looking all day for an example of use of the async pipe with an Observable that does not observe an array, nor a single string. I would like to use an observable with a dictionnary structure whose fields I would display and update thanks to the async pipe. Is it something stupid? I don’t understant why this case is never mentioned. Thank you for your time and your answer.

  • Celine Kessler

    I finally found the answer here : https://github.com/angular/angular/issues/6392

    The syntax for representing a nested field of a bigger structure is :
    {{(myService.myObservableStructure | async)?.myField}}

    The syntax for representing a nested array is :

    • Btroncone

      Sorry I wasn’t quicker, I’m glad you got it figured out! I will try to update the article with an example to avoid confusion in the future. 🙂

  • Ben Nadel

    I’m very intrigued by the idea of the async pipe. But, at the same time, I am not sure how often I’ll want to actually pipe an observable directly into my view. Meaning, in my components, I think i’ll often have more logic that just “take this object and stick it there.” Usually there’s loading indicators and other things that have to happen when a Promise / Observable returns.

    That said, I suppose you have both your component internals *and* your component view subscribe to the same observable so that you could handle logic internally and mark the change detector as well.

    • Btroncone

      I completely agree about promises, I doubt I will be using it much in that context.

      Regarding observables, this has not been an issue for me thus far. You can certainly create more observables within your component but all of the interesting work should still reside above the subscribe block. At that point you are still just piping observable output straight into the view.

      Do you have an example of the above situation? I would be interested in adapting it to see how it could be handled by the AsyncPipe alone. Thanks for the comment!

      • Ben Nadel

        I just mean that in my component logic, I might have something like this:

        inflightRequest.subscribe( function( newValue ) {
        . . . vm.isLoading = false;
        . . . vm.value = newValue;
        })

        But, then I suppose I could ALSO have this in my template:

        ngFor=”let item in inflightRequest | async”

        So, in essence, both my controller logic and my view logic are both subscribing to the return. But, I am not sure I love it 🙂

        • Btroncone

          Yeah, it’s an interesting situation.

          You could also have something along these lines:

          this.loading = inflightRequest.mapTo(false).startWith(true);

          and in template…

          ngFor=”let item in inflightRequest | async”
          {{loading | async}}

          Not sure the best option but it does make for good conversation. 🙂

  • Naveed Ahmed

    Great post Brian! I have a very basic question, before using Observable and async pipe, I had my items list surrounded by a div with an *ngIf on the length of the list, if the length is greater than 0, I display the list otherwise a message of no records found.

    = 0″>No records found

    = 0″>

    {{item.name}}

    I have now converted the list property in my component to an observable i.e.

    list$: Observable;

    Now in my template list$.length doesnt work, I mean the below doesn’t work any more.

    = 0″>No records found

    = 0″>

    {{item.name}}

    Can you please guide?

    • Btroncone

      I’m sorry, I must have missed this when first posted. You probably have figured it out by now but…

      If you need to access properties you can do it like (list$ | async).length

  • albanx

    should this pipe be impure to work?

    • Btroncone

      Yes, this is an impure pipe.

  • pasha

    Great post. I try to add some filter to async like this:
    *ngFor=”let item of getRemoteProducts() | async | priceRange:minVal:maxVal ” but it try to find value before list is loaded (priceRange pipe – is included to root of modules). Can you give me a hint how to solve this?