我的服务中有以下代码:
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 并在订阅中调用 getFacebookProfile() ,则一切正常。但我觉得这不是一个非常优雅的解决方案。
最佳答案
问题是 Promise 是急切的。当您编写可观察对象时,您正在调用 this.fb.login()
,并将返回的 Promise 传递到 fromPromise
中。
这意味着登录是在调用 loginWithFacebook
时启动的,而不是在其返回的可观察对象上调用 subscribe
时启动的。
如果您希望将 login
推迟到调用 subscribe
之前,您可以使用 defer
:
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);
}
});
}
有关使用可观察量和 Promise 的更多信息,请参阅 Ben Lesh 的文章:RxJS Observable interop with Promises and Async-Await
关于facebook - Observable switch/flatMap 立即触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47169421/