Subscribe VS Async pipe in Angular

·

6 min read

Subscribe VS Async pipe in Angular

The Difference between the async pipe and Subscribe in Angular.

I think we should always use async pipe when possible and only use **.subscribe** when the side effect is an absolute necessity.

So today I would like to discuss and give explanations which I think will help in understanding when to use async pipe and **subscribe**

  1. Best practices
  2. Observable and Rxjs
  3. Subscribe function
  4. Async pipe

Best practices

To summarize, these are the best practices to ensure the validity of the logic:

  1. Prefer assignments rather than callbacks, assign Observable rather than subscription,
  2. Let the framework terminate the Observable,
  3. Leverage the power of Angular components and Angular async pipe to code without asynchronously,
  4. Use libraries like reselect, rxjs to manipulate observable,
  5. Make sure the external variables used inside the Rx operators function are const.

Observable and RxJS

First, to understand the context, we need to understand what is observable.

Observable

Observable is an abstraction of an asynchronous stream of data. For example, when we look at Observable<string>, it represents a stream of strings which will be delivered one by one over the time.

Now, why would we care?

We need to care because the stream of data coming in an asynchronous fashion is extremely hard to think about. And it is even harder when multiple streams need to be combined. It becomes very error prone to code around it.

To do such operations, we can use RxJS operators.

RxJS

RxJS operators, which can be found under add/operator, allow us to operate directly on observables, modifying, combining, aggregating, filtering data of observables.we are safe as long as we stay in the Observable.

The power of RxJS is that each operation is assured to receive the output of the previous operation as its own input. This is an extremely powerful model that allows developers to easily follow the code logic making it predictable.

We must try to keep the observable as long as possible, combining it or modifying it using RxJS operators. As long as we stay within the observable, we do not need to think about the bigger picture. All we need to think about is what to do with the single string we receive. We don’t need to care about the fact that we will receive multiple values over time hence the safety.

But if we keep the Observable modifying it around, how do we display data? This is where we have been used to .subscribe.

Subscribe function

We pass the observable around, combining it, saving it to different variables with different combinations of operators but at the end, an Observable<T> is useless on its own. We need a way to “terminate” the observable and extract the type T out of it. That is what .subscribe is used for. To subscribe to the resulting stream and terminate the observable.

Now we could do the following:

costs: Cost[];

ngOnInit() {
    this.getCosts()
        .subscribe(costs => {
            this.costs = costs;
        });
}</span>

But as soon as it becomes more complex as if we need to get a list of Cost types to filter, it becomes hard to combine.

costs: Cost[] = [];
filter = "food";</span><span id="d6af" class="eb je hs de hb b jf jj jk jl jm jn jh s ji">ngOnInit() {
    this.getCosts()
        .subscribe(costs => {
            this.costs = costs.filter(e => e.type === this.filter);
        });</span><span id="35fa" class="eb je hs de hb b jf jj jk jl jm jn jh s ji">this.getFilter()
        .subscribe(filter => {
            this.filter = filter;
            this.costs = this.costs.filter(e => e.type === filter);
        });
}</span>

Now we can already appreciate the benefit of only subscribing when necessary and using them RxJS combinators:

ngOnInit() {
    this.getCosts()
        .combineLatest(this.getFilter())
        .subscribe(([costs, filter]) => {
            this.costs = costs.filter(e => e.type === filter);
        });
}</span>

As mentioned earlier, we are safe from asynchronously as long as we stay in the observable therefore we can do even better and never actually use subscribe by using async pipe.

Async Pipe

In order to keep the observable, we would transform it as such:

ngOnInit() {
    this.costs$ = this.getCosts()
        .combineLatest(this.getFilter())
        .map(([costs, filter]) => costs.filter(e => e.type === filter));
}</span>

The dollar $ is a convention to know that the variable is observable. Then to display from the UI, we would need to use the async pipe.

{{ costs$ | async }}</span>

The other benefit of using the async pipe is that it shows us the way to decompose our UI into components. Because we want to remove the observable, we want to make a data binding using [costs]="{{ costs$ | async }}" so that the component itself taking as input costs will be without observable. And this is the true beauty of the framework. By delaying the subscription till the end, we end up forcing ourselves in writing granular components that are abstracted from asynchronous.

Conclusion

Today we saw what was an Observable and how we could use leverage its power using RxJS. We also saw the differences between async pipe and subscription. Lastly, I shared my advice which is that we should always use async pipe when possible and only use **.subscribe** when the side effect is an absolute necessity as we are safe as long as we stay in the observable. The code terminating the observable should be the framework (Angular) and the last piece (the UI). Hope you like this post, see you next time!

Today we saw what was an Observable and how we could power of RxJS. We additionally observed the contrasts between async pipe and subscription. In conclusion, I shared my recommendation which is that we should always use async pipe when possible and only use **.subscribe** when the side effect is an absolute necessity as we are safe as long as we stay in the observable. The code terminating the observable should be the framework (Angular) and the last piece (the UI).