如何防止多个http请求同时触发
How to prevent multiple http requests from firing all at once
我有一组对象。对于每个对象,我需要触发一个异步请求(http 调用)。但是我只想同时有一定的最大请求数运行。另外,如果我可以在所有请求完成执行一些代码后有一个同步点,那就太好了(但不是必需的)。
我试过以下建议:
How to limit the concurrency of flatMap?
还有很多...我什至尝试制作自己的运算符。
这些页面上的答案太旧而无法使用我的代码,或者我不知道如何将所有内容放在一起以便所有类型都能很好地匹配。
这是我目前拥有的:
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()
?
顺便说一句:带 resultSelector
参数的 mergeMap
已弃用,所以我在没有它的情况下使用了 mergeMap
。
此外,mergeMap
的 obj
在 tap
中不可见,所以我不得不使用 tap
的参数
编辑 2:
确保您的观察员完成! (花了我一整天)
我曾经遇到过同样的问题。当我试图从服务器加载多个图像时。我不得不一个接一个地发送http请求。我使用 awaited promise 实现了预期的结果。这是示例代码:
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。打开控制台以查看它的运行情况。 :)
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'))
)
代码未经测试,但您明白了。如果需要任何错误或解释,请告诉我
您可以使用 mergeMap
to limit the number of concurrent inner subscriptions. Use 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 上的示例。
我有一组对象。对于每个对象,我需要触发一个异步请求(http 调用)。但是我只想同时有一定的最大请求数运行。另外,如果我可以在所有请求完成执行一些代码后有一个同步点,那就太好了(但不是必需的)。
我试过以下建议:
How to limit the concurrency of flatMap?
还有很多...我什至尝试制作自己的运算符。
这些页面上的答案太旧而无法使用我的代码,或者我不知道如何将所有内容放在一起以便所有类型都能很好地匹配。
这是我目前拥有的:
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()
?
顺便说一句:带 resultSelector
参数的 mergeMap
已弃用,所以我在没有它的情况下使用了 mergeMap
。
此外,mergeMap
的 obj
在 tap
中不可见,所以我不得不使用 tap
的参数
编辑 2:
确保您的观察员完成! (花了我一整天)
我曾经遇到过同样的问题。当我试图从服务器加载多个图像时。我不得不一个接一个地发送http请求。我使用 awaited promise 实现了预期的结果。这是示例代码:
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。打开控制台以查看它的运行情况。 :)
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'))
)
代码未经测试,但您明白了。如果需要任何错误或解释,请告诉我
您可以使用 mergeMap
to limit the number of concurrent inner subscriptions. Use 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 上的示例。