我有一个对象数组。对于每个对象,我需要触发一个异步请求(http调用)。但我只想同时运行一定数量的请求。另外,如果在所有请求执行完某些代码后都可以有一个同步点,那将是很好的(但不是必需的)。
我尝试了以下建议:
Limit number of requests at a time with RxJS
How to limit the concurrency of flatMap?
Fire async request in parallel but get result in order using rxjs
还有更多...我什至尝试创建自己的运算符。
这些页面上的答案太旧而无法使用我的代码,或者我不知道如何将所有内容放在一起,以便所有类型都很好。
这是我到目前为止所拥有的:
for (const obj of objects) {
this.myService.updateObject(obj).subscribe(value => {
this.anotherService.set(obj);
});
}
编辑1: 好吧,我想我们到了!有了 Julius 和 pschild 的答案(两者似乎均能正常工作),我设法限制了请求的数量。但是现在,它只会发射第一批4,而不会发射其余的。所以现在我有:
const concurrentRequests = 4;
from(objects)
.pipe(
mergeMap(obj => this.myService.updateObject(obj), concurrentRequests),
tap(result => this.anotherService.set(result))
).subscribe();
我在subscribe()
上做错什么了吗?
顺便说一句:不推荐使用带有mergeMap
参数的resultSelector
,所以我使用了不带mergeMap
的参数。
另外,obj
的{{1}}在mergeMap
中不可见,因此我不得不使用tap
的参数
编辑2:
确保观察者完整! (花了我一整天)
答案 0 :(得分:3)
您可以使用mergeMap
的第三个参数来限制并发内部订阅的数量。在所有请求完成后,使用finalize
执行一些操作:
const concurrentRequests = 5;
from(objects)
.pipe(
mergeMap(obj => this.myService.updateObject(obj), concurrentRequests),
tap(res => this.anotherService.set(res))),
finalize(() => console.log('Sequence complete'))
);
请参见Stackblitz上的示例。
答案 1 :(得分:2)
from(objects).pipe(
bufferCount(10),
concatMap(objs => forkJoin(objs.map(obj =>
this.myService.updateObject(obj).pipe(
tap(value => this.anotherService.set(obj))
)))),
finalize(() => console.log('all requests are done'))
)
代码未经测试,但是您可以理解。让我知道是否需要任何错误或解释
答案 2 :(得分:0)
我曾经遇到过同样的问题。当我尝试从服务器加载多个图像时。我不得不一次又一次发送http请求。我使用期待已久的承诺实现了预期的结果。这是示例代码:
async ngOnInit() {
for (const number of this.numbers) {
await new Promise(resolve => {
this.http.get(`https://jsonplaceholder.typicode.com/todos/${number}`).subscribe(
data => {
this.responses.push(data);
console.log(data);
resolve();
}
);
});
}
}
这里的主要思想是在收到响应后解决承诺。 使用这种技术,您可以提出自定义逻辑,以在所有请求完成后执行一种方法。
这里是stackblitz。打开控制台以查看操作。 :)