将 RXJS 用作级联的 forEach 循环?

Using RXJS like a cascaded forEach loop?

如何使用 RXJS 进行级联 forEach 循环?目前,我有 4 个包含简单字符串列表的可观察对象,称为 x1 - x4。我现在想要实现的是 运行 遍历所有变体,并调用带有变体数据对象的 REST-Api。通常,我会用 forEach 做类似的事情,但是如何用 RXJS 做呢?请看抽象代码:

    let x1$ = of([1,2]);
    let x2$ = of([a,b,c,d,e,f]);
    let x3$ = of([A,B,C,D,E,F]);
    let x4$ = of([M,N,O,P]);

    x1$.forEach(x1 => {
        x2$.forEach(x2 => {
            x3$.forEach(x3 => {
                x4$.forEach(x4 => {
                    let data = {
                        a: x1,
                        b: x2,
                        c: x3,
                        d: x4
                    }

                    return this.restService.post('/xxxx', data)
                })  
            })  
        })          
    })

RXJS 是否可以以一种优雅的方式实现类似的功能?

假设您有一个函数 combineLists,它表示将静态列表转换为请求可观察对象数组的逻辑的纯数组版本:

function combineLists(lists: unknown[][]) {
  const [x1s, x2s, x3s, x4s] = lists;

  // Calculate combinations, you can also use your forEach instead
  const combinations = x1s
    .flatMap(a => x2s
    .flatMap(b => x3s
    .flatMap(c => x4s
    .flatMap(d => ({a, b, c, d})))));
    
  return combinations.map(combination => this.restService.post('/xxxx', combination));
}

由于您的输入 observables 也是一次性的,我们可以使用例如forkJoin。这会等待它们全部完成,然后以它们各自的普通值运行。此时,您将返回使用首选方法计算组合。

forkJoin([x1$, x2$, x3$, x4$]).pipe(
  map(combineLists),
);

假设您的 REST 调用输入 return T,上面的代码生成 Observable<Observable<T>[]>。你如何从这里开始取决于你正在寻找什么数据结构/你想如何继续使用它。这似乎不再是你问题的一部分,但我还是会给出一些提示:

如果您想要 Observable<T>,您可以添加例如mergeAll() 运算符。这个 observable 将按照它们到达的顺序依次发出所有单个请求的结果。

forkJoin([x1$, x2$, x3$, x4$]).pipe(
  map(combineLists),
  mergeAll(),
);

如果您想要一个 Observable<T[]> 而不是将结果收集到单个发射中,您可以再次 forkJoin 生成的请求数组。这也保留了顺序。

forkJoin([x1$, x2$, x3$, x4$]).pipe(
  map(combineLists),
  switchMap(forkJoin),
);

一些警告:

  • 别忘了订阅让它真正做点什么。
  • 您应该确保处理所有 REST 调用的错误。这必须在调用本身发生,而不是在整个管道之后发生,除非您希望一个失败的请求破坏整个管道。
  • 请记住,forkJoin([]) 在空数组上不会发出任何东西。
  • 像这样触发大量请求可能意味着 API 应该随着请求数量呈指数增长而更改(如果可能)。