如何将 RXJS 中的嵌套调用展平并最终调用最后一个调用?
How to flatten the nested calls in RXJS and finally invoke one last call?
我们如何才能最好地压平以下调用。 RxJS 的新手,试图了解应该如何简化它。阅读 flatMap、forkJoin、switchMap 和 mergeMap,没有找到正确的集成路径,不确定在下面的场景中哪个是最好的。
const useful = [];
a.get('abc').
subscribe((abcdatas) => {
abcdatas.forEach(abcdata => {
if(abcdata.exist) {
b.get('def').
subscribe((defdatas) => {
useful.push(defdatas.someval);
});
}
});
})
if(useful.length) {
c.get('ghi').
subscribe((ghidata) => {
completed...
});
}
更新
在这里更新我的问题,感谢所有回复。有用的是一个全局结果数组,在我的例子中应该从嵌套调用中填充。并且最终应该传递给最后一个调用。
我正在尝试的步骤:
- a.get() => returns 数据
- b.get(adataset) => 如果数据集具有存在属性,则应为每个数据集执行请求,并填充稍后将使用的有用数组
- c.get(有用)=> 应该触发并退出。
使用 switchMap
或 mergeMap
之类的映射函数将一个请求的结果映射到下一个请求。使用forkJoin
同时执行多个请求。
所以对于一对多的场景,一般的想法是:
firstRequest().pipe(
switchMap(results => forkJoin(results.map(r => nextRequest(r))))
)
对于你的情况,应该是这样的:
useful = [];
a.get('abc').pipe(
switchMap(abcdatas => forkJoin(getUseFulRequests(abcdatas))),
tap(useful => useful.forEach(u => this.useful.push(u))),
switchMap(useful => useful.length ? c.get('ghi') : EMPTY)
).subscribe((ghidata) => {
completed...
});
function getUseFulRequests(abcdatas: AbcData[]): Observable<SomeVal>[] {
return abcdatas.reduce((acc, abcdata) => {
if (abcdata.exist) {
const request = b.get('def').pipe(
map(defdatas => defdatas.someval)
)
acc.push(request);
}
return acc;
}, []);
}
如果 getUseFulRequests(abcdatas)
returns 一个空数组或 useful.length == 0
.
这将不会发出任何东西
我相信处理这个问题的最好方法是使用高阶可观察量
考虑下面的代码
useful$ = a.get('abc').pipe(
mergeMap(abcdatas =>
abcdata.exist ? forkJoin(abcdatas.map(abcdata => b.get('def'))) : of(undefined)
),
map(defdatas => defdatas.flat()),
mergeMap(({ length }) => length ? c.get('ghi') : of(undefined))
);
useful$.subscribe({
next: () => {
// Completed...
}
})
我们首先将 a.get('abc')
的结果通过管道传输,然后使用 mergeMap 来测试是否 abcdata.exist
。如果它确实退出,我们 return forkJoin(abcdatas.map(abcdata => b.get('def')))
简单地说,这将合并从 abcdatas
上的 map 函数生成的可观察数组
map(defdatas => defdatas.flat()),
将数组转换为单个数组
注意:flat() 是在 ES2019 中引入的
接下来我们解构 length
属性 如果它存在我们 return 我们最终的可观察对象
我认为你想做的是:
a.get("abc").pipe(
mergeMap((abcdatas) => abcdatas.filter((abcdata) => abcdata.exist)), // let's create a stream with all those useful abcdata
mergeMap(abcdata => b.get('def')), // and for each one of those we perform a b.get request
toArray(), // once all the b.get requests have completed, emit a one value stream with an Array of those values values
concatMap(useful => useful.length ? c.get('ghi') : EMPTY) // let's concat that result with the final request
)
我们如何才能最好地压平以下调用。 RxJS 的新手,试图了解应该如何简化它。阅读 flatMap、forkJoin、switchMap 和 mergeMap,没有找到正确的集成路径,不确定在下面的场景中哪个是最好的。
const useful = [];
a.get('abc').
subscribe((abcdatas) => {
abcdatas.forEach(abcdata => {
if(abcdata.exist) {
b.get('def').
subscribe((defdatas) => {
useful.push(defdatas.someval);
});
}
});
})
if(useful.length) {
c.get('ghi').
subscribe((ghidata) => {
completed...
});
}
更新
在这里更新我的问题,感谢所有回复。有用的是一个全局结果数组,在我的例子中应该从嵌套调用中填充。并且最终应该传递给最后一个调用。
我正在尝试的步骤:
- a.get() => returns 数据
- b.get(adataset) => 如果数据集具有存在属性,则应为每个数据集执行请求,并填充稍后将使用的有用数组
- c.get(有用)=> 应该触发并退出。
使用 switchMap
或 mergeMap
之类的映射函数将一个请求的结果映射到下一个请求。使用forkJoin
同时执行多个请求。
所以对于一对多的场景,一般的想法是:
firstRequest().pipe(
switchMap(results => forkJoin(results.map(r => nextRequest(r))))
)
对于你的情况,应该是这样的:
useful = [];
a.get('abc').pipe(
switchMap(abcdatas => forkJoin(getUseFulRequests(abcdatas))),
tap(useful => useful.forEach(u => this.useful.push(u))),
switchMap(useful => useful.length ? c.get('ghi') : EMPTY)
).subscribe((ghidata) => {
completed...
});
function getUseFulRequests(abcdatas: AbcData[]): Observable<SomeVal>[] {
return abcdatas.reduce((acc, abcdata) => {
if (abcdata.exist) {
const request = b.get('def').pipe(
map(defdatas => defdatas.someval)
)
acc.push(request);
}
return acc;
}, []);
}
如果 getUseFulRequests(abcdatas)
returns 一个空数组或 useful.length == 0
.
我相信处理这个问题的最好方法是使用高阶可观察量
考虑下面的代码
useful$ = a.get('abc').pipe(
mergeMap(abcdatas =>
abcdata.exist ? forkJoin(abcdatas.map(abcdata => b.get('def'))) : of(undefined)
),
map(defdatas => defdatas.flat()),
mergeMap(({ length }) => length ? c.get('ghi') : of(undefined))
);
useful$.subscribe({
next: () => {
// Completed...
}
})
我们首先将 a.get('abc')
的结果通过管道传输,然后使用 mergeMap 来测试是否 abcdata.exist
。如果它确实退出,我们 return forkJoin(abcdatas.map(abcdata => b.get('def')))
简单地说,这将合并从 abcdatas
map(defdatas => defdatas.flat()),
将数组转换为单个数组
注意:flat() 是在 ES2019 中引入的
接下来我们解构 length
属性 如果它存在我们 return 我们最终的可观察对象
我认为你想做的是:
a.get("abc").pipe(
mergeMap((abcdatas) => abcdatas.filter((abcdata) => abcdata.exist)), // let's create a stream with all those useful abcdata
mergeMap(abcdata => b.get('def')), // and for each one of those we perform a b.get request
toArray(), // once all the b.get requests have completed, emit a one value stream with an Array of those values values
concatMap(useful => useful.length ? c.get('ghi') : EMPTY) // let's concat that result with the final request
)