我有一个功能,应该从一个API提取数据,然后使用结果从多个其他api获取数据。所有这些操作都必须先进行数据提取,但是某些后续调用可以并行运行,而其他一些调用则需要一个或多个并行调用返回的数据才能运行。目前,通过在另一个订阅中进行三个订阅(对于正在计数的一个函数中的四个订阅),我已经完成了一些工作,但这对我来说有点不对劲,我读过的所有内容都说这是反模式或完全错误。我需要一种方法来使所有这些东西以正确的顺序运行(在需要顺序的情况下)并返回我的数据。
我研究了几个rxjs选项,我认为我需要使用forkJoin(对于可以并行运行的项目)和mergeMap(对于依赖forkJoin结果的项目)进行某种组合。当前的设置是调用我的服务并进行订阅,然后在该订阅中forkForJoin并调用其他几个函数,对其进行订阅,然后在其中进行两次调用并订阅其他调用。
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可以解决所有其他问题,因此在我需要它时不可用,因此如果我记录它,则结果为“未定义”。最后,必须有一种方法可以很清楚地完成我想做的所有事情,而且只需一个订阅即可。
存在无效的无效代码,无效的无效代码和有效的不良代码。我无法决定哪一个是最糟糕的事情。
编辑:删除“记录”并替换为“内容”
答案 0 :(得分:2)
需要考虑的一些事情。尝试使用管道运算符。如果需要创建副作用,请点击。对于嵌套订阅,请尝试使用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];
}
);