2

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.

Kraken
  • 111
  • 11
  • Because async/await stops the JS main thread while executing the instructions that are inside the function. So, while doing it, DOM rendering is stuck. – Ricardo Machado Jun 08 '22 at 16:42
  • 1
    I don't recommend re-assigning the value to `this.people$` every time change is called. place your pipe on `people$` and call `sub.next()` of which `people$ = this.sub.asObservable().pipe(...)` – Get Off My Lawn Jun 08 '22 at 16:50
  • I don't see any noticeable difference in speed between both examples. The only difference I see is the white flickering in the async version, but that's because you are reassigning the `people$` property after each change. – akotech Jun 08 '22 at 16:53
  • to @GetOffMyLawn. it's no clear to me. wath's this.sub? – Kraken Jun 09 '22 at 13:31
  • 1
    @Kraken see my example here https://stackblitz.com/edit/stackoverflow-search-without-reassign – Get Off My Lawn Jun 09 '22 at 17:09

1 Answers1

0

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();
   }))
  );
}
Abel Valdez
  • 2,368
  • 1
  • 16
  • 33