如何将 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...
 });
}

更新

在这里更新我的问题,感谢所有回复。有用的是一个全局结果数组,在我的例子中应该从嵌套调用中填充。并且最终应该传递给最后一个调用。

我正在尝试的步骤:

  1. a.get() => returns 数据
  2. b.get(adataset) => 如果数据集具有存在属性,则应为每个数据集执行请求,并填充稍后将使用的有用数组
  3. c.get(有用)=> 应该触发并退出。

使用 switchMapmergeMap 之类的映射函数将一个请求的结果映射到下一个请求。使用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
)