RxJs:如何有条件地链接 BehaviorSubject 的可观察对象?
RxJs: How to conditionally chain observable of BehaviorSubject?
我有一个可观察的数据服务 (UserService),return是当前登录的用户。我遵循了本教程 - https://coryrylan.com/blog/angular-observable-data-services,它描述了使用 BehaviorSubject 立即 return 默认 currentUser,然后在加载或更改后发出真正的 currentUser。服务基本是这样的...
private _currentUser: BehaviorSubject<User> = new BehaviorSubject(new User());
public currentUser: Observable<User> = this._currentUser.asObservable();
constructor(private http: Http) {}
loadUser() { // app.component onInit and login component call this
return this.http.get('someapi.com/getcurrentuser')
.map(response => <User>this.extractData(response))
.do(
(user) => {
this.dataStore.currentUser = user;
this._currentUser.next(Object.assign(new User(), this.dataStore).currentUser);
},
(error) => this.handleError(error)
)
.catch(error -> this.handleError(error));
}
每当用户按 F5 键重新加载整个 spa 时,我都会遇到问题。当消费组件订阅 UserService 上的 currentUser 时,它会立即收到默认用户,而 UserService 会等待 api 调用以接收实际用户。 api 调用结束的那一刻,真实用户由 UserService 发出,所有订阅者都获得真实用户。但是,BehaviorSubject 发出的第一个值是默认值,它的 ID 始终为 "undefined",因此我们还不能进行下一个 api 调用。事实上,当真正的用户通过并且我可以使用 user.id 进行有效调用时,链接订阅永远不会发生并且我没有从响应中获取值。
我知道我在做一些愚蠢的事情,但我还没有弄清楚到底是什么。我只是偶然发现了 concatMap,但我不确定如何使用它。在我追求的同时,我想知道为什么下面的代码不起作用。我特别想知道为什么订阅永远不会触发,即使是在真正的用户进来之后,只是为了帮助我的新手理解 Observables。
this.userService.currentUser
.flatMap((user) => {
this.user = user;
// Need to NOT call this if the user does not have an id!!!
this.someOtherService.getSomethingElse(user.id); // user.id is always undefined the first time
})
.subscribe((somethingElse) => {
// This never gets called, even after the real user is emitted by the UserService
// and I see the getSomethingElse() call above get executed with a valid user.id
this.somethingElse = somethingElse;
});
如果您想忽略没有 id
的用户实例,请使用 filter
operator:
import 'rxjs/add/operator/filter';
this.userService.currentUser
.filter((user) => Boolean(user.id))
.flatMap((user) => {
this.user = user;
this.someOtherService.getSomethingElse(user.id);
})
.subscribe((somethingElse) => {
this.somethingElse = somethingElse;
});
关于"why the subscribe never fires",很可能是由于未定义id
引起的错误。您只将 next
函数传递给 subscribe
,因此任何错误都不会得到处理。如果发生错误,observable 将终止并取消订阅任何订阅者 - 因为这就是 observables 的行为方式 - 因此将不会收到任何具有已定义 id
属性的后续用户。
我有一个可观察的数据服务 (UserService),return是当前登录的用户。我遵循了本教程 - https://coryrylan.com/blog/angular-observable-data-services,它描述了使用 BehaviorSubject 立即 return 默认 currentUser,然后在加载或更改后发出真正的 currentUser。服务基本是这样的...
private _currentUser: BehaviorSubject<User> = new BehaviorSubject(new User());
public currentUser: Observable<User> = this._currentUser.asObservable();
constructor(private http: Http) {}
loadUser() { // app.component onInit and login component call this
return this.http.get('someapi.com/getcurrentuser')
.map(response => <User>this.extractData(response))
.do(
(user) => {
this.dataStore.currentUser = user;
this._currentUser.next(Object.assign(new User(), this.dataStore).currentUser);
},
(error) => this.handleError(error)
)
.catch(error -> this.handleError(error));
}
每当用户按 F5 键重新加载整个 spa 时,我都会遇到问题。当消费组件订阅 UserService 上的 currentUser 时,它会立即收到默认用户,而 UserService 会等待 api 调用以接收实际用户。 api 调用结束的那一刻,真实用户由 UserService 发出,所有订阅者都获得真实用户。但是,BehaviorSubject 发出的第一个值是默认值,它的 ID 始终为 "undefined",因此我们还不能进行下一个 api 调用。事实上,当真正的用户通过并且我可以使用 user.id 进行有效调用时,链接订阅永远不会发生并且我没有从响应中获取值。
我知道我在做一些愚蠢的事情,但我还没有弄清楚到底是什么。我只是偶然发现了 concatMap,但我不确定如何使用它。在我追求的同时,我想知道为什么下面的代码不起作用。我特别想知道为什么订阅永远不会触发,即使是在真正的用户进来之后,只是为了帮助我的新手理解 Observables。
this.userService.currentUser
.flatMap((user) => {
this.user = user;
// Need to NOT call this if the user does not have an id!!!
this.someOtherService.getSomethingElse(user.id); // user.id is always undefined the first time
})
.subscribe((somethingElse) => {
// This never gets called, even after the real user is emitted by the UserService
// and I see the getSomethingElse() call above get executed with a valid user.id
this.somethingElse = somethingElse;
});
如果您想忽略没有 id
的用户实例,请使用 filter
operator:
import 'rxjs/add/operator/filter';
this.userService.currentUser
.filter((user) => Boolean(user.id))
.flatMap((user) => {
this.user = user;
this.someOtherService.getSomethingElse(user.id);
})
.subscribe((somethingElse) => {
this.somethingElse = somethingElse;
});
关于"why the subscribe never fires",很可能是由于未定义id
引起的错误。您只将 next
函数传递给 subscribe
,因此任何错误都不会得到处理。如果发生错误,observable 将终止并取消订阅任何订阅者 - 因为这就是 observables 的行为方式 - 因此将不会收到任何具有已定义 id
属性的后续用户。