考虑到我有一个调用服务器并通过Observable返回用户数据的函数:
getUserById (id: number): Observable<User> {
return this.http.get('/users/' + id)
.map(response => response.json())
;
}
如何让它更像Promise?
问题是,在有人订阅返回的observable之前不会发出请求。此外,当完成多个订阅时,将多次调用服务器。
我想要的是:
调用getUserById()
后立即调用服务器(订阅应该是可选的,只有当调用者真的想要获取返回的值或者想知道请求何时完成时)
多个订阅不应产生多个请求,但应返回从服务器获取的相同值
通过这种方法,我将能够使这个功能起作用:
refreshUser (): Observable<User> {
return repository.getUserById(this.currentUser.id)
.map(user => this.currentUser = user)
;
}
调用refreshUser()
时,应该发出请求并评估this.currentUser = user
。如果我愿意,我可以订阅返回的observable以获取新数据,例如:
// Just refreshes the current user
refreshUser();
// Refreshes the current user and obtains fresh data
refreshUser().subscribe(user => console.log('Refreshed user', user));
我尝试在不同的组合中使用publish()
,refCount()
和share()
,但它只对第一个要求有帮助(即避免多次调用服务器),但是如何我可以将原始的可观察性变得热吗?
使用不同的选项进行进一步调查之后,似乎使getUserById()
热的解决方案无法解决它,因为我在不同级别上有两个映射函数(getUserById()
中的一个和{{1}中的一个})我需要它们两个来执行。为了解决这个问题,我需要以某种方式“推动”观察者从下到上。看起来每个级别都需要很多样板代码。
在承诺中,它看起来很简单:
refreshUser()
getUserById (id: number): Promise<User> {
return this.http.get('/users/' + id)
.map(response => response.json())
.toPromise()
;
}
是否有一个更简单的解决方案,RxJS或Promise实际上更适合这项工作?
答案 0 :(得分:2)
根据您的描述,您似乎可以执行以下操作:
getUserById (id: number): Observable<User> {
const observable = this.http.get('/users/' + id)
.map(response => response.json())
.publishReplay(1)
.refCount()
.take(1);
observable.subscribe();
return observable;
}
如果您多次订阅从getUserById
返回的相同Observable,您将始终获得相同的结果。
答案 1 :(得分:1)
您似乎需要使用或Subject
或BehaviorSubject
而不是正常的Oberservable。在您的情况下,BehaviorSubject
更好,因为它存储当前值。
声明两个变量,一个是普通User
类型,另一个是BehaviorSubject
User
:
currentUser:User;
userBSubject:BehaviorSubject<User>;
因为您需要BehaviorSubject
的初始值,所以可以在构造函数中初始化它:
constructor(){
this.userBSubject = new BehaviorSubject<User>(this.currentUser)
}
所以这就是魔术的来源。每次你需要修改(在你的情况下,#34;刷新&#34;)数据时,你会调用方法.next()
:
refreshUser() {
return repository.getUserById(this.currentUser.id)
.subscribe(user => {
this.userBSubject.next(user);
return this.userBSubject.asObservables()
});
}
然后你可以这样做:
// Just refreshes the current user
refreshUser();
// Refreshes the current user and obtains fresh data
refreshUser().subscribe(user => console.log('Refreshed user', user));