2017-11-08 15 views
2

私は私のサービスで次のコードを持っている:観察可能なスイッチ/ flatMap火災が瞬時に

public loginWithFacebook(): Observable<any> { 
    console.log('Login'); 
    return Observable.fromPromise(this.fb.login()).flatMap((userData) => { 
     return this.http.post(authFacebook, {access_token: userData.authResponse.accessToken}, { observe: 'response' }); 
    }).do((response: HttpResponse<any>) => { 
     const token = response.headers.get('x-auth-token'); 
     if (token) { 
     localStorage.setItem('id_token', token); 
     } 
    }); 
    } 

    getFacebookProfile():Observable<any> { 
    console.log("Get Profile"); 
    return Observable.fromPromise(this.fb.getLoginStatus()) 
     .filter((state) => state.status === 'connected') 
     .switchMapTo(Observable.fromPromise(this.fb.api('/me'))); 
    } 

をし、ログインが成功したら、後で私は、プロファイル情報を取得するために私のコンポーネントでそれを使用。

this.profileData = this.usersService.loginWithFacebook() 
    .flatMapTo(this.usersService.getFacebookProfile()); 

しかし、何らかの理由で、getFacebookProfile()はログインプロシージャが完了する前に即座に起動します。そして、私は認証エラーを取得します。また、プロファイル情報を表示するには、2回ログインする必要があります。

switchMapとflatMapは、前回の値が一度値を出すと、次の観測可能な値に切り替わると常に考えていました。 ここで何が間違っていますか?私は、サブスクリプションの最初の観察可能と呼んgetFacebookProfile()を購読している場合

--EDIT--

は、すべてが正常に動作します。しかし、それは私が感じる非常にエレガントなソリューションではありません。

答えて

3

問題は約束が熱望していることです。あなたはobservableを作成し、返された約束をfromPromiseに渡しているときにthis.fb.login()に電話しています。

これは、loginWithFacebookが呼び出されたときにログインが開始され、それが返すオブザーバブルにsubscribeが呼び出されたときではないことを示します。

あなたはsubscribeが呼び出されるまで、あなたがdeferを使用することができますloginを延期することにしたい場合:

public loginWithFacebook(): Observable<any> { 
    console.log('Login'); 
    return Observable.defer(() => Observable.fromPromise(this.fb.login())) 
    .flatMap((userData) => { 
     return this.http.post(authFacebook, { 
     access_token: userData.authResponse.accessToken 
     }, { observe: 'response' }); 
    }) 
    .do((response: HttpResponse<any>) => { 
     const token = response.headers.get('x-auth-token'); 
     if (token) { 
     localStorage.setItem('id_token', token); 
     } 
    }); 
} 

観測と約束の使用方法の詳細については、ベン・レッシュの記事を参照してください。RxJS Observable interop with Promises and Async-Await

+0

正常に動作するはずです。しかし、今私はそれを試したとき、私は同じ結果を得ました。なんらかの理由で即座に起動します。 –

+0

可観測チェーンを構築するときに約束している場所の** all **に 'defer'を使用する必要があります。 – cartant

0

それは働いていましたついに@ cartantの答えに感謝します。しかし何らかの理由で、私はそれを二重演算子で2回ラップする必要がありました。誰かがなぜそれをする必要があるのか​​を説明できるなら、私は感謝します。それはちょっと変だ。

public loginWithFacebook(): Observable<any> { 
    return Observable.defer(() => 
     Observable.defer(() => this.fb.login()).flatMap((userData) => 
     { 
      return this.http.post(authFacebook, {access_token: userData.authResponse.accessToken}, { observe: 'response' }); 
     }).do((response: HttpResponse<any>) => { 
      const token = response.headers.get('x-auth-token'); 
      if (token) { 
       localStorage.setItem('id_token', token); 
      } 
     }) 
    ); 
    } 

    getFacebookProfile():Observable<any> { 
    return Observable.defer(() => 
     Observable.defer(() => this.fb.getLoginStatus()) 
     .filter((state) => state.status === 'connected') 
     .switchMapTo(Observable.fromPromise(this.fb.api('/me'))) 
    ); 
    }