angular - RxJS beter sig inte som förväntat


Jag arbetar på en Angular 8-applikation som använder RxJS 6. Jag trodde att jag klarade mig ganska bra med RxJS, men idag stötte jag på något som får mig att tro att jag har en grundläggande missuppfattning om hur det fungerar.

Jag har följande prenumeration:

this.nudgePauseConnectivity$.pipe(
    tap(() => console.log(1)),
    withLatestFrom(this.hotspotPausedState$()),
    tap(() => console.log(2)),
    filter(([nudgePause, connectionPaused]) => connectionPaused === enums.HotspotPausedStateEnum.FALSE),
    tap(() => console.log(3)),
    switchMapTo(this._store.pipe(select(this._hotspotSelectors.selectUsername))),
    tap(() => console.log(4)),
    switchMap(username =>
        this._cabinApiV2Service.subscriberService.getRemainingConnectivityAllowance(username)
    ),
    tap(() => console.log(5)),
    map(remainingConnectivityAllowance => SubscriberConnectivityAllowanceTransformer.transform(
        remainingConnectivityAllowance
    ))
).subscribe(() => {/* Do something */});

nudgePauseConnectivity$ är ett ämne jag använder för att få kroppen av observabeln att köras, på det här sättet:

pauseConnectivity() {
    this.nudgePauseConnectivity$.next({});
}

this._hotspotSelectors.selectUsername är en NgRx-selektor, som om du inte har använt NgRx i en observerbar som returnerar värden från en store.

Mitt problem är detta: Jag trodde att uttrycket skulle köras en gång för varje värde som emitteras från this.nudgePauseConnectivity$. Jag skulle förvänta mig att se i konsolen:

1

2

3

4

5

Det verkar dock som att även om this.nudgePauseConnectivity$ inte avger ett värde, börjar uttryckets exekvering om this._store.pipe(select(this._hotspotSelectors.selectUsername)) avger ett värde, så jag ser denna typ av utskrift i konsolen:

1

2

3

4

5

4

5

Jag är helt förvirrad över detta! Jag vill aldrig att uttrycket ska börja köras i mitten: jag vill att uttrycket endast ska köras om this.nudgePauseConnectivity$ skickar ett värde, oavsett värdena på några uttryck i switchMaps eller andra högre ordningens observabla operatorer senare i kedjan.

Hur uppnår jag detta?

Svar #1

switchMap avbryter inte prenumerationen efter den första emissionen. Du borde göra det. Vi glömmer vanligtvis detta eftersom vi oftast har att göra med observables som bara sänder en emission, som http-klienten. Eftersom du har en ström som lever så länge din app lever, istället för:

switchMapTo(this._store.pipe(select(this._hotspotSelectors.selectUsername))),

du skulle kunna göra (för att inte avbryta all kedjning från nudgePauseConnectivity$ - detta kommer bara att begränsa utsläppen från switchMap till en enda utsläpp, men kommer att hålla prenumerationen på nudgePauseConnectivity$ aktiv):

switchMap(() => this._store.pipe(
 select(this._hotspotSelectors.selectUsername), 
 take(1)
)

Eller sätt bara take(1) i kedjan efter switchMapTo om du vill avbryta alla utsläpp efter det första (det kommer att avbryta prenumerationen på nudgePauseConnectivity$ efter det första utsläppet):

...
switchMapTo(this._store.pipe(select(this._hotspotSelectors.selectUsername))),
take(1),
...

Det är värt att ta en titt i andra delar av din kod för att se om du avregistrerar dig korrekt från alla observables som du använder (även de i Angular-formulär).