2015-12-09 4 views
5

Ich habe eine Observable in der ich eine andere beobachtbare konsumiere, aber die 2. Observable kann ich nicht lösen. Hier ist der Code:Wie kann ich ein Observable innerhalb eines anderen Observable auflösen? - rxjs

return Observable.fromPromise(axios(config)) 
     .map(res => { 
      return { 
       accessToken: res.data.access_token, 
       refreshToken: res.data.refresh_token     
      } 
     }) 
     .map(res => { 
      return { 
       me: getMe(res.accessToken), 
       accessToken: res.accessToken, 
       refreshToken: res.refreshToken     
      } 
     }) 

function getMe(accessToken) { 
    return Observable.fromPromise(axios.get({ 
     url: 'https://api.spotify.com/v1/me', 
    })); 
} 

Die getMe Funktion gibt einen Observable, aber es wird nie gelöst. Ich habe versucht, eine flatMap und eine concat hinzuzufügen, aber es ist immer noch nicht gelöst. Wie bekomme ich die getMe zu lösen?

Antwort

8

Bitte benutzen Sie die folgenden (auch ungetestet) versuchen:

function getMe(accessToken) { 
    return Rx.Observable.fromPromise(axios.get({ 
    url: 'https://api.spotify.com/v1/me', 
    })); 
}  

Rx.Observable.fromPromise(axios(config)) 
    .map((res) => { 
     return { 
      accessToken: res.data.access_token, 
      refreshToken: res.data.refresh_token     
     } 
    }) 
    .flatMap((res) => { 
     return getMe(res.accessToken).map((res2) => { 
      res.me = res2; 
      return res; 
     } 
    }) 
    .subscribe((data) => console.log(data)); 

Wie in der obigen Beitrag erwähnt, flatMap eine beobachtbare zurückgibt. map wird anschließend zum Zusammenführen von res mit dem Ergebnis res2 verwendet, das aus dem zweiten Versprechen stammt.

Beachten Sie auch, dass fromPromise eine kalte beobachtbar ist. Dies bedeutet, dass Sie ein Abonnement haben müssen, um Dinge zu initiieren. In Ihrem Fall, ich nehme an, Sie schon so etwas wie diese:

someFunction =() => { 
    return Rx.Observable.fromPromise(axios(config)) 
    ... 
    ... 
} 

someFunction.subscribe((data) => console.log(data)); 
+0

Interessanter Vorschlag. Könnte wertvoll sein, um es zu testen. Meiner Meinung nach besteht ein mögliches Problem darin, auf "res" von der Schließung zuzugreifen. Ich bin mir da nicht sicher, aber die anonyme Funktion mit 'res.Ich werde in seinem Körper nur dann ausgeführt/evaluiert, wenn "getMe" einen Wert ausgibt. Zu diesem Zeitpunkt frage ich mich, ob die Variable "res" noch ihren Wert behält. Ich kodiere das defensiv um dies herum, indem ich nur reine Funktionen in Verbindung mit Observablen verwende. Ich bin also interessiert zu wissen, ob ich zu vorsichtig bin. – user3743222

+0

Aus der Perspektive eines Abschlusses wird 'res' immer noch seinen Wert behalten (ich habe diese Technik schon einmal benutzt). Ich stimme zu, dass es am besten ist, einen defensiven Stil zu haben und gründlich zu testen. Als eine Randnotiz, wenn es eine zweite 'Rx.Observable.fromPromise (axios (config))' Ausführung vor 'getMe()' verrechnet, dann haben Sie 2 Abo-Ausführungen. Dies kann leicht mit 'flatMapLatest' behoben werden, wodurch sichergestellt wird, dass Sie immer die letzte 'getMe()' Antwort mit einer Subskriptionsausführung erhalten. – Jeremy

+0

fair genug. Danke für die Klarstellung. – user3743222

0

Beispielcode zu finden unten (UNTESTED !!). Einige Erklärungen:

  • die beobachtbare zurück von getMe nicht abgeflacht (‚Entschlossenheit‘ gehören zu der Welt der Versprechen), weil der map Betreiber nicht beobachtbaren abzuflachen. flatMap tun, aber Sie müssen es in der Form source.flatMap(function(x){return observable}) verwenden und hier, was Sie zurückgeben, ist eine kein Rx.Observable.
  • Also, um die getMe zu plätten verwenden wir eine flatMap.
  • Um die fehlenden Felder (accessToken und refreshToken) verwenden wir withLatestFrom auf den beobachtbaren, die das res Objekt emittieren wieder hinzufügen (res$).
  • Wir verwenden share, da wir zweimal res$ abonnieren, und wir möchten, dass alle Abonnenten die gleichen Werte sehen.

    var res$ = Observable 
        .fromPromise(axios(config)) 
        .map(function (res) { 
         return { 
         accessToken : res.data.access_token, 
         refreshToken : res.data.refresh_token 
         } 
        }) 
        .share(); 
    var getMe$ = res$.flatMap(function (res) {return getMe(res.accessToken)}); 
    var finalRes$ = getMe$.withLatestFrom(res$, function (getMe, res) { 
    return { 
        me   : getMe, 
        accessToken : res.accessToken, 
        refreshToken : res.refreshToken 
    } 
    }); 
    
    function getMe (accessToken) { 
        return Observable.fromPromise(axios.get({url : 'https://api.spotify.com/v1/me'})); 
    } 
    
+0

POJO = Plain Old Javascript Object – user3743222

+0

Vielen Dank für die Hilfe, aber dies scheint mehr gewunden als die Verwendung von 'Promises'. Es muss einen prägnanteren Weg geben. – jhamm

+0

Sicher mal sehen, was andere kommen. Frage: Warum verwenden Sie keine Versprechen und konvertieren dann zu beobachtbar, wenn Sie das gewünschte Ergebnis haben? 'Rx.Observable.fromPromise' macht das, auf diese Weise haben Sie das Beste aus beiden Welten. – user3743222

2

Wie @ user3743222 wies darauf hin, tut ein Observableresolve nicht in dem Sinne, dass ein Promise tut. Wenn Sie den Wert der getMe Methode möchten, müssen Sie die von ihm zurückgegebene Observable abonnieren.

return Observable.fromPromise(axios(config)) 
     .map(res => { 
      return { 
       accessToken: res.data.access_token, 
       refreshToken: res.data.refresh_token     
      } 
     }) 
     .flatMap(function(tokens) { 

      //FlatMap can implicitly accept a Promise return, so I showed that here 
      //for brevity 
      return axios.get({url : 'https://api.spotify.com/v1/me'}); 
     }, 

     //The second method gives you both the item passed into the first function 
     //paired with every item emitted from the returned Observable` 
     //i.e. axios.get(...) 
     function(tokens, response) { 
      return { 
      accessToken: tokens.accessToken, 
      refreshToken: tokens.accessToken, 
      //Here response is a value not an Observable 
      me: response 
      }; 
     }); 
Verwandte Themen