我有一个任务队列(长度为20个),其中每个任务都是一个要调用的ajax请求。
我想:
1)创建5个块(20/5 = 4个块)
2)执行每个块,其中块中的每个项将以1000毫秒的延迟执行。
3)当每个块项目完成时,等待3秒钟。
所以:
1 .. 1秒(↦绿色) .. 2 .. 1秒(↦绿色) .. 3 .. 1秒(↦绿色) .. 4 .. 1sec(↦green) .. 5 ..................... 3sec ..........
6 .. 1sec(↦绿色) .. 7 .. 1sec(↦green) .. 8 .. 1sec(↦green)。 .9 .. 1秒(↦绿色) .. 10 ..................... 3sec .. ........
...
11 .. 1sec(↦绿色) .. 12 .. 1sec(↦green) .. 13 .. 1sec(↦green)。 .14 .. 1秒(↦绿色) .. 15 ..................... 3sec .. ........
16 .. 1sec(↦绿色) .. 17 .. 1sec(↦green) .. 18 .. 1sec(↦green)。 .19 .. 1秒(↦绿色) .. 20
我确实设法做了一些事情:
使用:
from(this.httpCodes)
.pipe(bufferCount(5),
concatMap((i, y) => from(i).pipe(mergeMap(f => {
this.httpCodes[f.index].wasExecuted = true;
return this.ajaxAlike(f.data).pipe(
catchError(() => { return of(-1) }),
map((r) => ({ res: r, data: f }))
)
})
,delay(3000) )),
)
但它并没有像我预期的那样执行。我没有看到块中每个项目之间的延迟
问题:
为什么我会看到这么多请求,如何更改我的代码,以便一个块中的每个项目都会以1秒的延迟执行(绿色应该在每秒后出现),并且 - 在每个块之后,等待3秒钟?
答案 0 :(得分:4)
延迟运算符会延迟发出的项目。看起来你期望它发出物品,然后在发出下一个之前“睡眠”3秒钟。要实现这一目标,您可以连接空的延迟可观察。
您可以创建以下可管道 睡眠运算符:
const sleep = ms => concat(Rx.Observable.empty().pipe(delay(ms)))
使用如下:
const {concatMap, concat, delay, bufferCount} = Rx.operators;
const sleep = ms => concat(Rx.Observable.empty().pipe(delay(ms)));
const ajaxAlike = call => Rx.Observable.of(call).pipe(delay(500));
Rx.Observable.range(0, 20).pipe(
bufferCount(5),
concatMap(calls =>
Rx.Observable.from(calls).pipe(
concatMap(call => ajaxAlike(call).pipe(sleep(1000))),
sleep(3000)
)
)
)
.subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.7/Rx.js"></script>
答案 1 :(得分:2)
编辑:好的,我想我现在明白你的意思了。我更新了小提琴,以便所有的块部分并行执行,但是块相互等待完成。所以这应该可以解决问题:
const chunkSize = 5;
const requestsWithDelay = httpRequests.map(obs => obs.delay(1000));
let chunks = [];
for (let i = 0; i < requestsWithDelay.length; i += chunkSize) {
chunks.push(requestsWithDelay.slice(i, i + chunkSize));
}
const chunkedRequests = chunks.map(chunk => Rx.Observable.forkJoin(...chunk).delay(3000));
const parallelChunkRequest = Rx.Observable.concat(...chunkedRequests);
parallelChunkRequest.subscribe();
原始答案:
这样的东西会给你所需的延迟(给定httpRequests作为一个可观察的数组):
const requestsWithDelay = httpRequests.map((obs, idx) => {
let msDelay = 1000;
if ((idx + 1) % 5 === 0 && idx < httpRequests.length - 1) {
msDelay = 3000;
}
return obs.delay(msDelay);
});
const request = Rx.Observable.concat(...requestsWithDelay);
这应该有用,但不会有“实际”的可观察块。每个块中的请求不会并行执行(就像使用mergeMap一样),而是连续执行。
要获得httpRequests的可保存性,你可能会这样(但没有管道延迟):
const httpRequests = this.httpCodes.map(data => this.ajaxAlike(data));
但如果你想让这些块并行执行,你可以这样做:
let chunks = [];
for (let i = 0; i < requestsWithDelay.length; i += 5) {
chunks.push(requestsWithDelay.slice(i, i + 5));
}
const chunkedRequests = chunks.map(chunk => Rx.Observable.concat(...chunk));
const parallelChunkRequest = Rx.Observable.merge(...chunkedRequests);
我创建了demo Fiddle
但是为什么你需要在每个块之后延迟3秒,如果它们并行执行而不是彼此等待?