Rxjs:在发射后从多个可观察量中获取最新值
Rxjs: get latest values from multiple observables later after they emitted
我有多个可观察对象在页面的生命周期内发出值。例如:
chartData$: Observable;
tableData$: Observable;
filterData$: Observable;
用户可以随时单击 'Download' 按钮,并获得 JSON 组合最后从这些可观察量中的每一个发出的值:
downloadButtonClicked$.pipe(
combine chartData$, tableData$ and filterData$ // <- how do I get latest values here?
).subscribe(([chart, table, filter]) => downloadJson(chart, table, filter))
但是当这 3 个可观察对象中的任何一个作为页面生命周期的一部分发出值时,不应调用 downloadJson
函数,仅在下载点击时。
TLDR;
工作最优雅的解决方案(正如 Mike 所建议的)
https://stackblitz.com/edit/typescript-jm3zma?file=index.ts
combineLastest 将在所有可观察对象都发出后发出。您可以使用 switchMap 从 downloadButtonClicked$ 切换。
downloadButtonClicked$.pipe(
switchMap(
() => combineLatest([chartData$, tableData$, filterData$])
)
).subscribe(([chart, table, filter]) => downloadJson(chart, table, filter));
如果你想在每个源 Observable 完成之前从它们中的每一个获取最后一个值,你可以使用 forkJoin()
,它只会在所有源 Observable 完成后发出一次。
如果你想在每个源 Observable 的每个发射上发射,你可以使用 combineLatest
.
编辑:
您可以将每个源 Observable 与 shareReplay(1)
链接起来,这样当您订阅它们时,您将获得最新的值。
const chartDataShared$ = chartData$.pipe(shareReplay(1));
tableDataShared$ = ...;
filterDataShared$ = ...;
combineLatest([chartDataShared$, tableDataShared, filterDataShared$]).pipe(
take(1)
);
通过这种方式,您将获得从它们中的每一个发出的最新值。然而,这意味着在你的代码的其他部分你需要使用例如。 chartDataShared$
而不是 chartData$
.
你可以这样做:
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
.
您可以简单地使用 withLatestFrom
。
downloadButtonClicked$.pipe(
withLatestFrom(chartData$, tableData$, filterData$)
).subscribe(([_, chart, table, filter]) => downloadJson(chart, table, filter))
仅当 downloadButtonClicked$
发出并将其值与 chartData$
、tableData$
和 filterData$
.
的最新值组合时,observable 才会发出
我有多个可观察对象在页面的生命周期内发出值。例如:
chartData$: Observable;
tableData$: Observable;
filterData$: Observable;
用户可以随时单击 'Download' 按钮,并获得 JSON 组合最后从这些可观察量中的每一个发出的值:
downloadButtonClicked$.pipe(
combine chartData$, tableData$ and filterData$ // <- how do I get latest values here?
).subscribe(([chart, table, filter]) => downloadJson(chart, table, filter))
但是当这 3 个可观察对象中的任何一个作为页面生命周期的一部分发出值时,不应调用 downloadJson
函数,仅在下载点击时。
TLDR;
工作最优雅的解决方案(正如 Mike 所建议的) https://stackblitz.com/edit/typescript-jm3zma?file=index.ts
combineLastest 将在所有可观察对象都发出后发出。您可以使用 switchMap 从 downloadButtonClicked$ 切换。
downloadButtonClicked$.pipe(
switchMap(
() => combineLatest([chartData$, tableData$, filterData$])
)
).subscribe(([chart, table, filter]) => downloadJson(chart, table, filter));
如果你想在每个源 Observable 完成之前从它们中的每一个获取最后一个值,你可以使用 forkJoin()
,它只会在所有源 Observable 完成后发出一次。
如果你想在每个源 Observable 的每个发射上发射,你可以使用 combineLatest
.
编辑:
您可以将每个源 Observable 与 shareReplay(1)
链接起来,这样当您订阅它们时,您将获得最新的值。
const chartDataShared$ = chartData$.pipe(shareReplay(1));
tableDataShared$ = ...;
filterDataShared$ = ...;
combineLatest([chartDataShared$, tableDataShared, filterDataShared$]).pipe(
take(1)
);
通过这种方式,您将获得从它们中的每一个发出的最新值。然而,这意味着在你的代码的其他部分你需要使用例如。 chartDataShared$
而不是 chartData$
.
你可以这样做:
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
.
您可以简单地使用 withLatestFrom
。
downloadButtonClicked$.pipe(
withLatestFrom(chartData$, tableData$, filterData$)
).subscribe(([_, chart, table, filter]) => downloadJson(chart, table, filter))
仅当 downloadButtonClicked$
发出并将其值与 chartData$
、tableData$
和 filterData$
.