如何解决如何在嵌套的foreach中继续操作之前确保所有异步调用完成
首先,我知道这个问题已经被回答过很多次了,但是我一直无法找到如何在特定情况下实现它的方法。
一方面,我有一种与此类似的方法
getSomeInfoFromAnApi(param1: number,param2: number): Observable<any> {
// Call some REST API and return an Observable
}
另一方面,该方法正以这种方式在其他地方调用:
data.forEach(graphic =>
graphic.series.forEach(serie => {
if (serie.channelValueType === 'string') {
this.myService.getSomeInfoFromAnApi(graphic.modelId,serie.channelId).subscribe(myResponse => {
// this is much more complex,just keeping it small for the sake of the example
// but the important thing here is that a member of the 'serie' item is being modified
serie.points = myResponse;
});
}
})
);
// graphics$ is defined as a BehaviorSubject
this.graphics$.next(data);
这里的问题是对BehaviorSubject上的 next 的调用发生的时间比预期的要早得多,因为 getSomeInfoFromAnApi 是异步调用。
最好的方法是确保仅在处理完数据集合中的所有元素之后才进行调用,这意味着对getSomeInfoFromAnApi的所有可能的调用都已响应并执行了预订的代码。
初始方法
根据我在stackoverflow上找到的一些答案,这是我到目前为止已经实现的方法,但是我确定必须有更好的方法:
data.forEach((graphic,dataIndex) =>
graphic.series.forEach((serie,seriesIndex) => {
if (serie.channelValueType === 'string') {
this.myService.getSomeInfoFromAnApi(graphic.modelId,serie.channelId).subscribe(myResponse => {
// this is much more complex,just keeping it small for the sake of the example
// but the important thing here is that a member of the 'serie' item is being modified
serie.points = myResponse;
if(data.length === dataIndex + 1 && graphic.series.length === seriesIndex + 1) {
this.graphics$.next(data);
}
});
}
else {
if(data.length === dataIndex + 1 && graphic.series.length === seriesIndex + 1) {
this.graphics$.next(data);
}
}
})
解决方法
我认为类似这样的方法可能会适合您的情况。
我们可以使用data
从您的from()
创建一个流,而不是使用BehaviorSubject并手动将其发射到该流中,而使用mergeMap()
处理订阅您的api调用,然后在所有调用完成后使用toArray()
将所有结果组合到一个数组中。
graphics$ = from(data).pipe(
mergeMap(graphic => from(graphic.series).pipe(
filter(series => series.channelValueType === 'string'),mergeMap(series => this.myService.getSomeInfoFromAnApi(graphic.modelId,series.channelId).pipe(
map(myResponse => ({...series,points: myResponse}))
),),toArray()
)
,
下面是一个如何实现的示例({BehaviorSubject
留在原处):
from(data)
.pipe(
mergeMap(graphic => from(graphic.series)
.pipe(
filter(series => series.channelValueType === 'string'),series.channelId)
.pipe(
map(points => ({ ...series,points }))
)
),toArray(),map(series => ({ ...graphic,series }))
)
),)
.subscribe(graphics => this.graphics$.next(graphics))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。