Rxjs:在发出多个观测值之后获取最新值

问题描述

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

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,filter))

但是,当这3个可观察变量中的任何一个页面生命周期中发出值时,仅在单击“下载”时,才不应调用downloadJson函数

TLDR;

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

解决方法

您可以这样做:

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

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

注意:只有所有chartData$tableData$filterData$都发出了第一个值后,才能创建订阅。如果您仍然需要在这种情况下触发下载,则可以使用defaultIfEmpty

,

如果您想在每个可观察源完成之前从它们中获取最后一个值,则可以使用forkJoin(),它们在所有它们都完成之后只会发出一次。

如果要从可观察的每个源排放每个排放,则可以使用combineLatest

编辑:

您可以将每个可观察的来源与shareReplay(1)链接起来,这样,当您订阅它们时,您将获得最新的价值。

const chartDataShared$ = chartData$.pipe(shareReplay(1));
tableDataShared$ = ...;
filterDataShared$ = ...;

combineLatest([chartDataShared$,tableDataShared,filterDataShared$]).pipe(
  take(1)
);

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

,

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

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

您可以简单地使用withLatestFrom

downloadButtonClicked$.pipe(
  withLatestFrom(chartData$,filterData$)
).subscribe(([_,chart,filter))

可观察对象仅在downloadButtonClicked$发出并将其值与chartData$tableData$filterData$的最新值组合时才发出。