Async pipe vs. Subscribe. Why is async pipe version slower?

Issue

I’ve created an app to search employes that use observables.
It’s very simple:
template for subscribe

<div class="row row-cols-1 row-cols-md-6 g-2">
    <ng-container *ngIf="emps.length">
        <div class="col" *ngFor="let emp of emps">
            <div class="card h-100">
                <img *ngIf="emp.image" [src]="emp.image" class="card-img-top" alt="image">
                <div class="card-body">
                    <span *ngIf="emp.actived" class="badge rounded-pill bg-success"
                            style="position: absolute;top: 2px;right: 2px;">&#10003;
                    </span>
                    <h5 class="card-title">{{emp.name| uppercase}}</h5>
                    <!-- <pre class="card-text">{{emp.phones}}</pre> -->
                </div>
            </div>
        </div>
    </ng-container> 
</div>

Component:

emps: IToList[] = [];

change(){//e: HTMLInputElement) {
  this.service.getPeople(this.searchTerm).pipe(
     map(data => data.map(d => {
         let c = new Person(d._id, d.actived, d.name, d.phones, d.image);
         return c.getPerson();
     }))
  ).subscribe(data=>this.emps=data);
}

It works fine for me:

enter image description here

The async pipe version.
template:

<div class="row row-cols-1 row-cols-md-6 g-2">
    <ng-container *ngIf="people$|async as emps">
        <div class="col" *ngFor="let emp of emps">
            <div class="card h-100">
                <img *ngIf="emp.image" [src]="emp.image" class="card-img-top" alt="image">
                <div class="card-body">
                    <span *ngIf="emp.actived" class="badge rounded-pill bg-success"
                            style="position: absolute;top: 2px;right: 2px;">&#10003;
                    </span>
                    <h5 class="card-title">{{emp.name | uppercase}}</h5>
                    <!-- <pre class="card-text">{{emp.phones}}</pre> -->
                </div>
            </div>
        </div>
    </ng-container> 
</div>

Component:

people$!: Observable<IToList[]>;
      
change(){//e: HTMLInputElement) {
   this.people$ = this.service.getPeople(this.searchTerm).pipe(
      map(data => data.map(d => {
           let c = new Person(d._id, d.attivo, d.nominativo, d.telefoni, d.immagine);
           return c.getPerson();
      }))
  ); 
}

enter image description here

Why is the app more responsive when I’m manually subscribing instead of using an async pipe?

Updated 10/06/2022

The image src is a base64 string and its size is 3mb.

Solution

When you use async Pipe you will use ChangeDetectionStrategy in OnPush it will improve your performance.

Async pipe it`s better in most of the cases because it is in charge to handle the subscription and unsuscription and notify which reactive part of the code is going to be rendered. Also you prevent possible memory leaks.

Even you can remove the ngif and the container where is the main subscription just by adding the async pipe in the *ngFor="let emp of (people$ | async)"

***************************** Edit ********************************************

The main problem in you code that is mentioned by @Get Off My Lawn.
Each time the search term change your observable is been recreated and it is the difference between with your 2 examples.

What You can do is in the ngOninit add the people$ observable with the form control of the search input then adding a switchMap operator to execute the service call then you will have the same observable and subscription always

ngOnini{
  this.people$ = this.form.get('searchInput').valueChanges.pipe(
   switchMap(searchTerm => this.service.getPeople(this.searchTerm)),
   map(data => => data.map(d => {
     let c = new Person(d._id, d.actived, d.name, d.phones, d.image);
     return c.getPerson();
   }))
  );
}

Answered By – Abel Valdez

Answer Checked By – Timothy Miller (AngularFixing Admin)

Leave a Reply

Your email address will not be published.