javascript - Hur man gör kedjesekvensen i rxjs


Jag skulle vilja göra något som:

this._myService.doSomething().subscribe(result => {
  doSomething()
});
.then( () => dosthelse() )
.then( () => dosanotherthing() )

Så jag skulle vilja kedja .then som i ett löfte. Hur skulle jag göra det i Rxjs?

this._myService.getLoginScreen().subscribe( result => {
      window.location.href = MyService.LOGIN_URL;
      /// I would like to wait for the site to load and alert something from       the url, when I do it here it alerts the old one
    });
   .then (alert(anotherService.partOfTheUrl())


getLoginScreen() {
  return this.http.get(myService.LOGIN_URL)
.flatMap(result => this.changeBrowserUrl())
.subscribe( result => //i want to do sth when the page is loaded//);
}

changeBrowserUrl(): Observable<any> {
return Observable.create( observer => {
window.location.href = myService.LOGIN_URL;
observer.next();
});
}

Svar #1

Motsvarigheten till then för observables skulle vara flatMap. Du kan se några exempel på användning här :

  • RxJS Promise-sammansättning (överföring av data)
  • Varför behöver vi använda flatMap?
  • RxJS-sekvens motsvarande promise.then()?

För ditt exempel skulle du kunna göra något som:

this._myService.doSomething()
  .flatMap(function(x){return functionReturningObservableOrPromise(x)})
  .flatMap(...ad infinitum)
  .subscribe(...final processing)

Var uppmärksam på typerna av vad dina funktioner returnerar, eftersom för att kedja observables med flatMap behöver du returnera ett löfte eller en observable.

Svar #2

Uppdaterad rxjs-lösning

Rxjs har förändrats ganska mycket sedan detta besvarades.

  • flatMap är nu mergeMap

    • Eller switchMap, de är mestadels utbytbara men det är bra att känna till skillnaden
  • .do() är nu tap()
  • Kedjning görs nu inuti en .pipe(). All manipulation bör göras inuti denna pipe

    • Du kan kedja rör om det behövs (t.ex. en variabel mappar en array av användare. En annan variabel tar den första variabeln och mappar den en andra gång)

Gör något efter att det ursprungliga samtalet har gjorts

Scenario

  • Gör ett HTTP-anrop (t.ex. autentiseringskontroll)
  • När det samtalet har avslutats, navigera till en annan sida
this._myService.getAuthenticated()
  .pipe(
    tap(result => this._myService.navigateToHome())
  )
  .subscribe()

Kedja flera samtal

Scenario

  • Gör ett HTTP-anrop (t.ex. autentiseringskontroll)
  • Gör ett andra samtal för att hämta mer information
  • Navigera efter att båda samtalen har avslutats
this._myService.getAuthenticated()
  .pipe(
    // The Authentication call returns an object with the User Id
    switchMap(user => this._myService.getUserInfo(user.id))
    // After the user has been loaded, navigate
    tap(user => this._myService.navigateToHome())
  )
  .subscribe()

Notering om exemplen ovan: Jag antar att dessa anrop är HTTP som avregistrerar sig efter att ha anropats en gång. Om du använder en live-observable (t.ex. en ström av användare), se till att du antingen avregistrerar dig eller använder takeUntil/first-operatorer.

Svar #3

Om dosthelse eller dosanotherthing returnerar ett råvärde, är operatören att använda map. Om det är ett observerbart, är operatören flatMap (eller motsvarande).

Om du vill göra något imperativt. Jag menar utanför den asynkrona bearbetningskedjan, kan du använda do-operatorn.

Förutsatt att dosthelse returnerar ett observerbart och dosanotherthing ett råobjekt, skulle din kod vara:

this._myService.doSomething()
  .do(result => {
    doSomething();
  })
  .flatMap( () => dosthelse() )
  .map( () => dosanotherthing() );

Observera att om du returnerar resultatet av subscribe-metoden, kommer det att motsvara ett prenumerationsobjekt och inte en observable. Ett prenumerationsobjekt är främst för att kunna avbryta observablen och kan inte ta del av den asynkrona processkedjan.

Faktum är att de flesta gånger prenumererar du i slutet av kedjan.

Så jag skulle refaktorera din kod på detta sätt:

this._myService.getLoginScreen().subscribe( result => {
  window.location.href = MyService.LOGIN_URL;
  /// I would like to wait for the site to load and alert something from       the url, when I do it here it alerts the old one
  alert(anotherService.partOfTheUrl()
});

getLoginScreen() {
  return this.http.get(myService.LOGIN_URL)
    .flatMap(result => this.changeBrowserUrl())
    .do( result => //i want to do sth when the page is loaded//);
}

changeBrowserUrl(): Observable<any> {
  return Observable.create( observer => {
    window.location.href = myService.LOGIN_URL;
    observer.next();
  });
}

Relaterade artiklar