angular - 如何使用 rxjs 运算符和转换链接多个依赖订阅?
问题描述
我有一个函数应该从一个 api 中提取数据,然后使用结果从几个额外的 api 中获取数据。第一次数据拉取对所有这些都是必要的,但一些后续调用可以并行运行,而其他调用则需要一个或多个并行调用返回的数据才能运行。目前,我通过在另一个订阅中进行三个订阅来完成其中的一些工作(对于那些正在计数的人来说,这是一个函数中的四个订阅),但这对我来说是错误的,我读过的所有内容都说它是要么是反模式,要么是完全错误的。我需要一种方法来让所有这些事情以正确的顺序运行——在需要顺序的地方——并返回我的数据。
我研究了几个 rxjs 选项,我认为我需要使用 forkJoin(对于可以并行运行的项目)和 mergeMap(对于依赖于 forkJoin 结果的项目)的某种组合。当前设置是调用我的服务并订阅,然后在该订阅中 forkJoin 并调用其他几个函数,订阅该函数并在其中再进行两次调用并订阅其他调用。
getThingFromService(id: number): any {
const drinks = {};
this.thingService.getThingById(id)
.subscribe((thing) => {
this.thing = thing;
forkJoin([
this.getTea(thing.tea.id),
this.getCoffee(thing.coffee.id),
this.getSoda(thing.soda.id)
])
.subscribe((data) => {
drinks.tea = data[0];
drinks.coffee = data[1];
drinks.soda = data[2];
this.getCoffeeTypeById(drinks.coffee.bean.id)
.subscribe((bean) => {
drinks.coffeeBean = bean;
})
this.getSodaTypeById(drinks.soda.flavors.id)
.subscribe((flavor) => {
drinks.sodaFlavor = flavor;
});
});
)}
}
getTea(id: number) {
return this.thingService.getTea(id);
}
getCoffee(id: number) {
return this.thingService.getCoffee(id);
}
getSoda(id: number) {
return this.thingService.getSoda(id);
}
getCoffeeTypeById(id: number) {
return this.otherService.getCoffee(id);
}
getSodaTypeById(id: number) {
return this.yetAnotherService.getSoda(id);
}
这段代码的一切都困扰着我。首先,它读起来很混乱,而且不是很清楚。接下来,这是一个大大简化的版本。实际函数大约有 90 行。然后,它不会 100% 起作用。我认为 getSodaTypeById 正在解决其他所有问题,因此在我需要它时不可用,所以如果我记录它的结果是“未定义”。最后,必须有某种方法来完成我想做的所有事情,并且只需一个订阅即可。
有有效的坏代码,无效的坏代码,以及有效的坏代码。我无法决定哪一个是最糟糕的事情。
编辑:删除“记录”并替换为“事物”
解决方案
有些事情要考虑。尝试使用管道运算符。如果您需要创建副作用,请使用点击。对于嵌套订阅,请尝试 switchMap。此外,您可能不需要仅返回服务的额外方法。
这是一个快速可行的解决方案。一切顺利。
链接到示例https://stackblitz.com/edit/angular-rxjs-nested-subscriptions?file=src/app/app.component.ts
this.thingService.getThingById(id).pipe(
tap((thing) => {
this.thing = thing;
}),
switchMap(_ => forkJoin([
// NOTE: not sure where record comes from
// if it is related to thing then it can be get passed down
this.thingService.getTea(record.tea.id),
this.thingService.getCoffee(record.coffee.id),
this.thingService.getSoda(record.soda.id)
])),
switchMap(([tea, coffee, soda]) => forkJoin([
this.getCoffeeTypeById(coffee.bean.id),
this.getSodaTypeById(soda.flavors.id)
]))).subscribe((data) => {
drinks.coffeeBean = data[0];
drinks.sodaFlavor = data[1];
}
);
推荐阅读
- react-native - net::ERR_FILE_NOT_FOUND (反应原生图像调整器)
- eclipse - 无法在 Eclipse 中使用 Kotlin 项目运行 Spring Boot
- python - python flask和html javascript从mysql返回响应并显示
- python - python更改bash目录mac
- spring-data-elasticsearch - Spring Data Elasticsearch 使用 BigDecimal 作为 id
- c - 将 2 个数组的总和存储到一个简单的 int 变量中
- angular - 在不提供格式的情况下无法将西班牙日期转换为时刻对象
- python - (Python)网站加载硒,但在进行结帐后连接变得“不安全”
- javascript - Laravel 发布请求 api 不起作用
- html - Angular 1.xx 中的全名格式