【问题标题】:Are observables the right solution for requests that depend on data from one another?对于依赖于彼此数据的请求,可观察对象是正确的解决方案吗?
【发布时间】:2020-03-10 16:04:09
【问题描述】:

我有两个需要集成的 API。 一个我控制,另一个我不控制。

目前,我有一个网络应用程序需要从两个 API 获取用户数据并将它们组合起来。这在用户登录时发生一次。

Web 应用程序是用 Angular 构建的,Observables 也是内置的,但我不太擅长 observables,对于应该是一个简单的用例来说,它们感觉非常复杂。

下面的代码向身份提供者发出请求,从该提供者那里获取一个值,并在我的 API 中查询具有相同值的用户,然后在该用户和相关实体上加载数据,以便它可以显示在网络应用程序中。

基本上,我需要呈现用户及其母公司的组合视图。我只能通过用户的超媒体链接访问公司,并且如果不先在身份提供者中查找用户,我就无法知道他们。我需要发出所有这些请求的数据链是身份验证详细信息 => 用户详细信息 => 公司 - 我查找身份验证详细信息,使用其中的值来查找用户,并获得用户,然后我查看建立用户的公司。

我写的函数感觉很笨拙和幼稚。有没有更好的方法来使用 RxJS 做到这一点?

getUserData() {
        this.authService.getUser$()
            .pipe(take(1))
            .subscribe(
                profile => {
                    this.authProfile = profile;
                    this.getUserByAuthId(encodeURI(profile.sub))
                        .pipe(take(1))
                        .subscribe(user => {

                            this.userProfile = user;

                            if (user._links.employer) {
                                this.http.get<Company>(user._links.employer.href)
                                    .pipe(take(1))
                                    .subscribe(
                                        company => {
                                            this.company = company;
                                        }
                                    );
                            }
                });
            });
    }

【问题讨论】:

    标签: angular rxjs


    【解决方案1】:

    尝试将concatMap 用作it does not subscribe to the next observable until the previous completes

    return this.authService.getUser$()
        .pipe(
            concatMap((res: a1) => {           
                this.getUserByAuthId(encodeURI(res.sub))
            }),
            concatMap((res: a2) => {           
                this.http.get<Company>(res._links.employer.href)
            })
        ).subscribe((res: a3) => {
            // your logic here
    });
    

    【讨论】:

      【解决方案2】:

      是的,嵌套的subscribes 不好,因为它们会导致回调地狱并且不可取消。

      在这种情况下,您需要利用 switchMap。 SwitchMap 允许您有条件地切换到新的 observable。

      试试:

      import { of } from 'rxjs';
      import { switchMap } from 'rxjs/operators';
      ......
      getUserData() {
        this.authService.getUser$().pipe(
          take(1),
          switchMap(profile => {
            this.authProfile = profile;
            return this.getUserByAuthId(encodeURI(profile.sub)),
          }),
          take(1),
          switchMap(user => {
            this.userProfile = user;
            if (user._links.employer) {
              return this.http.get<Company>(user._links.employer.href);
            } else {
              return of(undefined);
            }
          }),
        ).subscribe(company => {
          // assign either undefined to company or the value of the previous HTTP call
          this.company = company;
        });
      }
      

      【讨论】:

        【解决方案3】:

        为了可读性,我更喜欢异步等待:

        getUserData() {
            this.authProfile = await this.authService.getUser$()
                    .pipe(take(1)).toPromise();
            this.userProfile = await this.getUserByAuthId(encodeURI(this.authProfile.sub))
                    .pipe(take(1)).toPromise();
            if (this.userProfile._links.employer) {
                this.company = this.http.get<Company>(this.userProfile._links.employer.href)
                        .pipe(take(1)).toPromise();
            }
        } 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-07-07
          • 2020-01-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多