Angular 在返回数据之前等待订阅完成

Jes*_*ssy 5 observable angular

您好,有一个非常简单的函数,可以调用端点来检索我的用户,我在标头中使用它来显示连接的用户,但不想在每次渲染标头时都调用端点。

所以我正在尝试这样的事情:

public getUser(): User {
    if (!this.user) {
     
      this.http.get<User>(environment.apiRoot + '/me').subscribe(res => {
        this.setUser(res);
        return this.user.value;
      }, err => {

      });
    } else {
      return this.user.value;
    }
  }
Run Code Online (Sandbox Code Playgroud)

具有以下setUser功能:

public setUser(u: User): void {
    if (!this.user) {
      this.user = new BehaviorSubject(u);
    } else {
      this.user.next(u);
    }
  }
Run Code Online (Sandbox Code Playgroud)

还有BehaviorSubjectprivate user: BehaviorSubject<User>;

在我的标头组件中,我这样称呼它ngOnInit

this.user = this.appState.getUser();
console.log(this.user);
Run Code Online (Sandbox Code Playgroud)

但console.log中的用户始终是未定义的,为什么它不等待函数中的订阅getUser

Dan*_*l B 9

您有一个使用混合反应式和命令式编程来调用的异步函数。当涉及异步函数时,您应该继续使用反应式方法,而不是尝试确定某个代码何时完成,而只是等待它完成,然后调用回调或负责的处理程序。

在您的代码中,该getUser()函数是一个async函数,因为您有内部http.get()调用。将http.get()返回一个Observable,您subscribe不必在函数内使用它。observable相反,您应该做的是从函数中返回内部,以及subscribe您真正需要它的地方。

我们可以像下面这样重写您的getUser函数(请注意,不需要命令式setUser函数)

public getUser(): Observable<User> {
    return this.http.get<User>(environment.apiRoot + '/me');
}
Run Code Online (Sandbox Code Playgroud)

并在您的外部范围内订阅它,例如

this.appState.getUser().subscribe(user => {
    console.log(user)
});
Run Code Online (Sandbox Code Playgroud)

更进一步来说,这也使得在模板中使用可观察量变得更加容易。

假设您将返回的可观察值分配给变量 ,user$您甚至不必订阅它!

只要让用户喜欢

this.user$ = this.appState.getUser();

获取您的 observable,然后在您的模板中使用async管道让 Angular 自动订阅和取消订阅。

<span>Hello, my name is {{user$ | async}}!</span>