typescript - Angular/RxJS - Finns det ett RxJS-pipe för startad ström?


Jag försöker skapa ett sätt att visa och dölja laddningsskärmen dynamiskt när jag löser någon ström.

Här är min nuvarande kod:

this.requestService
        .get<Checkout>(`check/${orderNumber}`)
        .pipe(
            tap(() => this.startLoading()),  //i think this isnt the right way to use this pipe
            finalize(() => this.endLoading())
        )
        .subscribe(
            data => {
                data.orderNumber = orderNumber
                this.checkout.next(data)
            },
            error => {
                this.notification.warning(error)
            }
        )

Det förväntade resultatet är att när min ström startar, visas en laddningsskärm med startLoading() och när operationen är klar, döljs laddningen med endLoading().

Min fungerande kod:

this.startLoading() //basically calling function before i create the stream

this.requestService
        .get<Checkout>(`check/${orderNumber}`)
        .pipe(                
            finalize(() => this.endLoading())
        )
        .subscribe(
            data => {
                data.orderNumber = orderNumber
                this.checkout.next(data)
            },
            error => {
                this.notification.warning(error)
            }
        )

Använder jag denna tap-pipe korrekt? Finns det en annan pipe som löser detta bättre?

Vad är det bästa sättet att göra detta med RxJS?

Svar #1

I ditt första exempel kör din tap efter att din HTTP-förfrågan har slutförts.

I slutändan skulle du bara kalla this.startLoading() innan du startar HTTP-förfrågan.

this.startLoading();
this.requestService.get<Checkout>(`check/${orderNumber}`).pipe(
  finalize(() => this.endLoading())
).subscribe(() => {

});

Om du verkligen vill kalla this.startLoading() i en pipe kan du kalla den innan HTTP-förfrågan startar genom att börja med din egen observable:

return of(null).pipe(
  tap(() => this.startLoading()),
  concatMap(() => this.requestService.get<Checkout>(`check/${orderNumber}`)),
  finalize(() => this.endLoading())
).subscribe(() => {

});

Men då är det egentligen inte mycket poäng med att göra det.

Så din tap-syntax är korrekt, det är bara det att den inte körs när du tror att den borde.

Svar #2

Om du vill utföra bieffekter på varje observerbar prenumeration kan du omvandla källan med defer().

import { defer } from 'rxjs';

...

defer(() => {
  this.startLoading();
  return this.requestService.get<Checkout>(`check/${orderNumber}`);
}).pipe(
    finalize(() => this.endLoading())
  )
  .subscribe(...);