将 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 应该随着请求数量呈指数增长而更改(如果可能)。
如何使用 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 应该随着请求数量呈指数增长而更改(如果可能)。