我的服务中有以下代码:
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()也会立即触发。我收到了身份验证错误。此外,我必须登录两次才能显示个人资料信息。
我一直认为,一旦前一个发出一个值,switchMap和flatMap只会切换到下一个observable。 我在这里做错了什么?
- 编辑 -
如果我订阅了第一个Observable并在订阅中调用getFacebookProfile(),一切正常。但我觉得这不是一个非常优雅的解决方案。
答案 0 :(得分:3)
问题在于承诺是渴望的。在撰写观察者时,您正在调用fromPromise
,并且您将返回的承诺传递给loginWithFacebook
。
这意味着在调用subscribe
时启动登录,而不是在它返回的observable上调用login
时启动。
如果您希望在调用subscribe
之前推迟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);
}
});
}
,则可以使用$stateProvider
:
template <typename S>
S * findID([string or int] ID){
for (typename vector<S*>::collectionsIter element = collection.begin() ; element != collection.end(); ++element)
if((*element)->getID() == ID) return *element;
return NULL;
}
有关使用可观察和承诺的更多信息,请参阅Ben Lesh的文章:defer
答案 1 :(得分:0)
最后感谢@ cartant的回答。但是,出于某种原因,我不得不用defer运算符包装它两次。如果有人能解释为什么有必要这样做,我将感激不尽。这有点奇怪。
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')))
);
}