Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance of using same observable in multiple places in template with async pipe

Tags:

angular

rxjs

In my component template I am calling async pipe for same Observable in 2 places.

Shall I subscribe to it and use returned array in my template or using async pipe for same Observable in multiple places of template has no negative effect to performence?

like image 722
Bogac Avatar asked Nov 22 '16 12:11

Bogac


People also ask

Do you prefer using the async pipe or subscribe approach and why?

The AsyncPipe is quite the handy little tool. And I think it's reasonable to say that a well-designed Angular application should never need to subscribe to an Observable. The async pipe can take care of subscribing and unsubscribing while we worry about more important stuff.

Is Observable lazy?

Observables are "lazy", meaning if no one is listening, nothing happens.

Is Observable asynchronous?

An observable produces values over time. An array is created as a static set of values. In a sense, observables are asynchronous where arrays are synchronous. In the following examples, → implies asynchronous value delivery.

Does pipe subscribe to Observable?

Async pipelinkThe AsyncPipe subscribes to an observable or promise and returns the latest value it has emitted.


2 Answers

Every use of observable$ | async will create a new subscription(and therefor an individual stream) to the given observable$ - if this observable contains parts with heavy calculations or rest-calls, those calculations and rest-calls are executed individually for each async - so yes - this can have performance implications.

However this is easily fixed by extending your observable$ with .share(), to have a shared stream among all subscribers and execute all those things just once for all subscribers. Don't forget to add the share-operator with import "rxjs/add/operator/share";

The reason why async-pipes don't share subscriptions by default is simply flexibility and ease of use: A simple .share() is much faster to write than creating a completely new stream, which would be required if they were to be shared by default.

Here is a quick example

@Component({     selector: "some-comp",     template: `         Sub1: {{squareData$ | async}}<br>         Sub2: {{squareData$ | async}}<br>         Sub3: {{squareData$ | async}}     ` }) export class SomeComponent {     squareData$: Observable<string> = Observable.range(0, 10)         .map(x => x * x)         .do(x => console.log(`CalculationResult: ${x}`)         .toArray()         .map(squares => squares.join(", "))         .share();  // remove this line and the console will log every result 3 times instead of 1 } 
like image 178
olsn Avatar answered Oct 22 '22 00:10

olsn


Another way of avoiding multiple subscriptions is to use a wrapping *ngIf="obs$ | async as someName". Using olsn's example

    @Component({         selector: "some-comp",         template: `           <ng-container *ngIf="squareData$ | async as squareData">             Sub1: {{squareData}}<br>             Sub2: {{squareData}}<br>             Sub3: {{squareData}}           </ng-container>`     })     export class SomeComponent {         squareData$: Observable<string> = Observable.range(0, 10)             .map(x => x * x)             .do(x => console.log(`CalculationResult: ${x}`)             .toArray()             .map(squares => squares.join(", "));      } 

It's also cool because it cleans out the template a bit too.

like image 44
Roy Art Avatar answered Oct 21 '22 22:10

Roy Art