javascript 如何在另一个 Observable 中解析一个 Observable?- rxjs

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34190650/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 17:21:37  来源:igfitidea点击:

How do I resolve an Observable inside of another Observable? - rxjs

javascriptrxjs

提问by jhamm

I have an Observablein which I consume another observable, but the 2nd ObservableI can't get to resolve. Here is the code:

我有一个Observable我使用另一个 observable,但第二个Observable我无法解决。这是代码:

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',
    }));
}

The getMefunction returns an Observable, but it is never resolved. I have tried to add a flatMapand a concat, but it still isn't resolved. How do I get the getMeto resolve?

getMe函数返回一个Observable,但它永远不会被解析。我试图添加 aflatMap和 a concat,但仍然没有解决。我该getMe如何解决?

回答by Jeremy

Did you try the following (Also untested):

您是否尝试过以下操作(也未经测试):

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));

As mentioned in the above post, flatMapreturns an observable. mapis subsequently used to merge reswith the result res2returned from the second promise.

如上flatMap一篇文章所述,返回一个可观察的对象。map随后用于resres2第二个承诺返回的结果合并。

Also note that fromPromiseis a cold observable. This means that you must have a subscription to initiate things. In your case, I presume you already have something like this:

另请注意,这fromPromise是一个冷的 observable。这意味着您必须订阅才能启动。在你的情况下,我想你已经有了这样的东西:

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

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

回答by paulpdaniels

As @user3743222 pointed out, an Observabledoes not resolvein the sense that a Promisedoes. If you want the value you of the getMemethod you will need to subscribe to the Observablereturned by it.

正如@user3743222 指出的那样, anObservable不像resolveaPromise那样。如果您想要该getMe方法的值,您将需要订阅Observable它返回的值。

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
          };
        });

回答by user3743222

Sample code to find below (UNTESTED!!). Some explanations :

下面的示例代码(未经测试!!)。一些解释:

  • the observable returned by getMeis not flattened ('resolve' belong to the world of promises) because the mapoperator does not flatten observables. flatMapdo, but you need to use it in the form source.flatMap(function(x){return observable})and here what you return is a POJOnot a Rx.Observable.
  • So, to flatten the getMewe use a flatMap.
  • To add back the missing fields (accessTokenand refreshToken) we use withLatestFromon the observable who emitted the resobject (res$).
  • We use shareas we subscribe twice to res$, and we want all subscribers to see the same values.

    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'}));
    }
    
  • 返回的 observablegetMe没有扁平化('resolve' 属于 promise 的世界),因为map操作符没有扁平化 observables。flatMap做,但你需要在表单中使用它,在source.flatMap(function(x){return observable})这里你返回的是一个POJOnot a Rx.Observable
  • 因此,为了展平getMe我们使用flatMap.
  • 为了添加缺失的字段(accessTokenrefreshToken),我们withLatestFrom在发射res对象的可观察对象上使用(和res$)。
  • 我们使用shareas 我们订阅了两次res$,我们希望所有订阅者看到相同的值。

    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'}));
    }