【问题标题】:Rxjs: get latest values from multiple observables later after they emittedRxjs:在多个可观察对象发出后获取最新值
【发布时间】:2020-12-26 22:26:41
【问题描述】:

我有多个在页面生命周期内发出值的可观察对象。例如:

chartData$: Observable;
tableData$: Observable;
filterData$: Observable;

用户可以随时单击“下载”按钮,并获取结合了每个可观察对象最后发出的值的 JSON:

downloadButtonClicked$.pipe(
    combine chartData$, tableData$ and filterData$    // <- how do I get latest values here?
).subscribe(([chart, table, filter]) => downloadJson(chart, table, filter))

但是,当这 3 个 observable 中的任何一个发出值作为页面生命周期的一部分时,不应调用 downloadJson 函数,仅在点击下载时调用。

TLDR;

工作最优雅的解决方案(如 Mike 所建议) https://stackblitz.com/edit/typescript-jm3zma?file=index.ts

【问题讨论】:

    标签: rxjs rxjs6 rxjs-pipeable-operators


    【解决方案1】:

    你可以这样做:

    combineLatest([chartData$, tableData$, filterData$]).pipe(
      switchMap(result => downloadButtonClicked$.pipe(map(() => result)))
    ).subscribe(([chart, table, filter]) => {
      downloadJson(chart, table, filter);
    });
    

    每当chartData$tableData$filterData$ 发出一个新值时,它将创建一个新的内部订阅downloadButtonClicked$,并传递新数据。

    注意:在所有chartData$tableData$filterData$ 发出它们的第一个值之前,不会创建订阅。如果您需要在这种情况下仍然触发下载,那么您可以使用defaultIfEmpty

    【讨论】:

      【解决方案2】:

      如果您想在每个源 Observable 完成之前从它们中的每一个中获取最后一个值,您可以使用 forkJoin(),它只会在它们全部完成后发出一次。

      如果你想在每个源 Observable 的每次发射中发射,你可以使用combineLatest

      编辑:

      您可以将每个源 Observable 与 shareReplay(1) 链接起来,因此当您订阅它们时,您将获得最新的值。

      const chartDataShared$ = chartData$.pipe(shareReplay(1));
      tableDataShared$ = ...;
      filterDataShared$ = ...;
      
      combineLatest([chartDataShared$, tableDataShared, filterDataShared$]).pipe(
        take(1)
      );
      

      通过这种方式,您将获得每一个发出的最新值。然而,这意味着在你代码的其他部分你需要使用例如。 chartDataShared$ 而不是 chartData$

      【讨论】:

      • 我想在单击“下载”时获取值。有点像每个 observable 的“当前状态”。
      • 好的,那有什么问题?
      • 不是在他们完成时。而不是每次排放。仅在单击按钮时。
      • 查看更新。但是,它需要更改您的代码。
      • 谢谢。但“下载”按钮不应该是一次性使用。用户应根据需要多次点击和下载。
      【解决方案3】:

      您可以简单地使用withLatestFrom

      downloadButtonClicked$.pipe(
        withLatestFrom(chartData$, tableData$, filterData$)
      ).subscribe(([_, chart, table, filter]) => downloadJson(chart, table, filter))
      

      observable 只会在 downloadButtonClicked$ 发出并将其值与来自 chartData$tableData$filterData$ 的最新值组合时发出。

      【讨论】:

        【解决方案4】:

        combineLastest 将在所有可观察对象都发出后发出。您可以使用 switchMap 从 downloadButtonClicked$ 切换。

        downloadButtonClicked$.pipe(
           switchMap(
             () => combineLatest([chartData$, tableData$, filterData$])
           )
        ).subscribe(([chart, table, filter]) => downloadJson(chart, table, filter));
        

        【讨论】:

        • 当输入的 observables 被其他操作触发时,这也会调用 downloadJson。但我只希望在单击“下载”时调用它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-24
        相关资源
        最近更新 更多