使可观察的行为像RxJS中的promise一样?

Sla*_* II 5 rxjs reactivex angular

考虑到我有一个调用服务器并通过Observable返回用户数据的函数:

getUserById (id: number): Observable<User> {
  return this.http.get('/users/' + id)
    .map(response => response.json())
  ;
}
Run Code Online (Sandbox Code Playgroud)

我如何使其表现得更像诺言?

问题是,只有有人订阅了返回的可观察对象,才会发出请求。另外,完成多个订阅后,服务器将被多次调用。

我想要的是:

  • 在被调用时立即调用服务器getUserById()(订阅应该是可选的,只有在调用者确实想要获取返回值或在请求完成时才知道的情况下)

  • 多个订阅不应产生多个请求,而应返回从服务器获得的相同值

使用这种方法,我将能够使此功能起作用:

refreshUser (): Observable<User> {
  return repository.getUserById(this.currentUser.id)
    .map(user => this.currentUser = user)
  ;
}
Run Code Online (Sandbox Code Playgroud)

调用时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));
Run Code Online (Sandbox Code Playgroud)

我尝试使用publish()refCount()并且share()以不同的组合使用,但是它仅对第一个要求有所帮助(即避免多次调用服务器),但是如何使原始的可观察性变热呢?


更新资料

经过使用不同选项的进一步研究之后,似乎使用getUserById()热解决方案无法解决该问题,因为我在不同级别上有两个映射函数(一对一getUserById()和一对in refreshUser()),并且我需要它们都执行。为了解决这个问题,我需要以某种方式从下到上“推动”可观察对象。看起来每个级别都需要大量样板代码。

在诺言中,它看起来非常简单:

getUserById (id: number): Promise<User> {
  return this.http.get('/users/' + id)
    .map(response => response.json())
    .toPromise()
  ;
}
Run Code Online (Sandbox Code Playgroud)
refreshUser (): Promise<User> {
  return repository.getUserById(this.currentUser.id)
    .then(user => {
      this.currentUser = user;
      return user;
    })
  ;
}
Run Code Online (Sandbox Code Playgroud)

使用RxJS是否有更简单的解决方案,或者Promises实际上更适合这项工作?

Coz*_*ure 1

看起来您需要使用 a 或Subjector aBehaviorSubject而不仅仅是普通的 Oberservable。就您而言, aBehaviorSubject更好,因为它存储当前值。

声明两个变量,一个是普通User类型,另一个是 a BehaviorSubjectof User

currentUser:User;
userBSubject:BehaviorSubject<User>;
Run Code Online (Sandbox Code Playgroud)

因为您需要 的初始值BehaviorSubject,所以您可以在构造函数中初始化它:

constructor(){
  this.userBSubject = new BehaviorSubject<User>(this.currentUser)
}
Run Code Online (Sandbox Code Playgroud)

所以这就是神奇的地方。每次您需要修改(在您的情况下,“刷新”)数据时,您都会调用该方法.next()

refreshUser() {
    return repository.getUserById(this.currentUser.id)
      .subscribe(user => {
        this.userBSubject.next(user);
        return this.userBSubject.asObservables()
      });
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

// Just refreshes the current user
refreshUser();

// Refreshes the current user and obtains fresh data
refreshUser().subscribe(user => console.log('Refreshed user', user));
Run Code Online (Sandbox Code Playgroud)