如何嵌套多个可观察对象/订阅

时间:2019-12-30 19:43:35

标签: angular typescript firebase rxjs

1。问题

我正在尝试为博客创建一种不断变化的语言流,总的来说,这是这样的:

  1. 用户单击触发事件(Subject)(即语言更改)的按钮。
  2. 此语言更改用于根据该语言向Firebase查询正确的页面。

如果我分别执行每个步骤,然后用户更改语言,则该查询将不会被触发,因为它不知道事件刚刚发生。因此,我认为这应该是某种嵌套的订阅/可观察的。我错了吗?

2。到目前为止,我的代码

我尝试了嵌套订阅,但是没有用。我相信这是由于发现bug所致。现在,这就是我要尝试的:

this.headerService.langChanged.pipe(
  map(
    (newLang: string) => {
      this.db
        .collection<AboutMePage>(
          this.aboutMeCollectionName, 
          ref => ref.where('lang', '==', newLang)
        )
        .valueChanges();
  })
)
  .subscribe(
    value => {
      this.aboutMe = value[0]
    }
  );

headerService.langChangedSubject<string>

此用例是否有rxjs运算符? concat似乎是一个不错的候选者,但是它会等待上一个Observable结束,但在这种情况下却没有。还有一个事实是,我必须将参数传递到下一个可观察的...

2 个答案:

答案 0 :(得分:2)

我认为可以使用concatswitchMapmergeforkJoin等中的任何一种为您提供有效的解决方案。这实际上取决于您想要的小东西例如并发。我在这里使用forkJoin整理了一个Stackblitz的小例子:https://stackblitz.com/edit/angular-xyf8a6

您可以在控制台中看到每个内部Observable的不同计时,以验证使用forkJoin的时间,以便只花费最慢的时间即可观察到。

还有我的订阅:

this.langChanged
  .subscribe(newLang => {
    console.log(`language changed ${newLang}`);
    this.cancelLangChange.next();
    forkJoin(
      this.getUserName(newLang), 
      this.getUserBio(newLang), 
      this.getUserCreationDate(newLang)
    )
      .pipe(takeUntil(this.cancelLangChange))
      .subscribe(([username, bio, userCreationDate]) => {
        this.aboutMe.username = username;
        this.aboutMe.bio = bio;
        this.aboutMe.userCreationDate = userCreationDate;
      });
  });

我还添加了第二个Subject cancelLangChange,如果用户仍在加载第一个更改时选择了另一种语言,则该取消是为了取消forkJoin订阅。

答案 1 :(得分:0)

我基本上通过使用pipemap使其正常工作。 map操作将使用第一个可观察值基于前者的参数生成另一个。然后,我们以嵌套方式进行订阅,最终将为我们提供所需的数据。

this.aboutMeSubscription = this.headerService.langChanged.pipe(
  map(
    (newLang: string) => {
      return this.db
        .collection<AboutMePage>(
          this.aboutMeCollectionName, 
          ref => ref.where('lang', '==', newLang)
        )
        .valueChanges();
  })
)
  .subscribe(
    langChangedAboutMeObs => {
      this.langChangedSubscription = langChangedAboutMeObs
        .subscribe(
          (value: AboutMePage[]) => {
            this.aboutMe = value[0];
          }
        );
    }
  );

我也将Subject更改为BehaviorSubject,因此甚至在用户执行任何操作之前就已经发出了初始值。最后,重要的是要取消订阅ngOnDestroy上的两个订阅。