W Angular jedną z bardziej eleganckich metod subskrypcji do strumieni jest użycie async pipe.
Dzięki temu nie potrzebujemy pamiętać, aby się odsubskrybować w metodzie ngOnDestroy i nie mamy potencjalnych wycieków pamięci.
<div class="company-address">
<h3>Address</h3>
<h4>{{ company$ | async }}</h4>
<p>{{ address.city }} {{ address.zipCode }}</p>
<p>{{ address.street }}</p>
<p>{{ address.phone }}</p>
</div>
Doskonale wiemy, że jeżeli na widoku użyjemy w różnych miejscach kilka razy async pipe dla tego samego observabla, to będziemy mieli kilka subskrypcji (możemy to zaobserwować m.in. w konsoli), co niestety obniża wydajność naszej aplikacji.
Wyzwanie:
Co by było, gdybyśmy potrzebowali tego samego strumienia użyć w pięciu albo dziesięciu miejscach ?! 🙂
<p>Conctact us: {{ (address$ | async).phone }} or email!</p>
<div *ngIf="address$ | async as address" class="company-address">
<h3>Address</h3>
<h4>{{ company$ | async }}</h4>
<p>{{ address.city }} {{ address.zipCode }}</p>
<p>{{ address.street }}</p>
<p>{{ address.phone }}</p>
</div>
Jak widać na załączonym kodzie powyżej, address został pobrany dwukrotnie z uwagi na użycie dwa razy async pipe. Nie jest to dobra praktyka.
Rozwiązanie 1:
Pomocna może być tutaj dyrektywa strukturalna *ngIf. Można ją wykorzystać np. do użycia observabli z async pipe w kilku miejscach jednocześnie w wygodny sposób.
<ng-container *ngIf="address$ | async as address">
<p>Conctact us: {{ address.phone }} or email!</p>
<div class="company-address">
<h3>Address</h3>
<h4>{{ company$ | async }}</h4>
<p>{{ address.city }} {{ address.zipCode }}</p>
<p>{{ address.street }}</p>
<p>{{ address.phone }}</p>
</div>
</ng-container>
Zaletą tego rozwiązania jest poprawienie jakości kodu, oraz jego wydajności.
Rozwiązanie 2:
Innym rozwiązaniem, które może nam pomóc rozwiązać powyższe wyzwanie, jest skorzystanie z jednego z operatorów RxJs, jakim jest shareReplay. Dzięki cache-owaniu, zapamiętuje on ostatnio przychodzące wiadomości, przez co nie powiela ponownego wysłania np. żądań HTTP.
Aby zapewnić uniknięcie podwójnej subskrypcji, wystarczy powyższy operator zastosować w następujący sposób. Wyświetli nam w konsoli tylko jedną subskrypcję do naszego adresu, mimo użycia kilku async pipe w widoku HTML.
ngOnInit(): void {
this.address$ = of(this.addressApi).pipe(
tap(address => console.log('address', address)),
shareReplay()
);
}
Podsumowanie:
Przedstawiłem tutaj dwa sposoby na radzenie sobie z wielokrotnym wykorzystaniem strumieni. Oczywiście, istnieją też inne możliwości rozwiązania tego samego problemu. 🙂
Jeżeli potrzebujesz, już teraz wykorzystaj kod i dołącz do swojego projektu, nie robiąc niepotrzebnych async pipe w wielu miejscach i popraw wydajność swojej aplikacji. ?
Zostaw komentarz