如果您想将其放入单个链中,您可以使用 connect() 运算符:
const obsA$ = range(5).pipe(
concatMap((v) => of(v).pipe(delay(Math.random() * 2000)))
);
const MIN_DELAY = 1000;
let observerReceivedTime = new Date().getTime();
obsA$
.pipe(
startWith(null),
connect((shared$) => {
let lastEmissionTime = null;
return shared$.pipe(
concatMap((value) => {
let delayedValue$;
if (!lastEmissionTime) {
// Don't delay the first emission.
delayedValue$ = of(value);
} else {
const delayBetweenValues = new Date().getTime() - lastEmissionTime;
// Wait for at least `MIN_DELAY`.
delayedValue$ =
delayBetweenValues > MIN_DELAY
? of(value)
: of(value).pipe(delay(MIN_DELAY - delayBetweenValues));
}
return delayedValue$.pipe(
// Remember time when the last value was reemited.
tap(() => (lastEmissionTime = new Date().getTime())),
);
})
);
})
)
.subscribe((v) => {
const now = new Date().getTime();
console.log(
`observer receives emission with at least ${MIN_DELAY}ms delay:`,
now - observerReceivedTime,
'value:',
v
);
observerReceivedTime = now;
});
现场演示:https://stackblitz.com/edit/rxjs-wmfetc?devtoolsheight=60&file=index.ts
我正在使用 RxJS 7 connect() 运算符来创建一个作用域变量 lastEmissionTime,所以我不需要产生任何副作用(尽管说实话链会更短一些并且更容易理解) .
基本上,它只是测量上一次发射和当前发射之间的时间,并将delay() 调整为始终至少为MIN_DELAY。
在观察者回调中,我只是测量时间戳以证明延迟始终至少为 1000 毫秒,如您所愿。
编辑:这是使用mergeScan 的替代方法,我认为这更好:
obsA$
.pipe(
startWith(null),
mergeScan(
([_, lastEmissionTime], currValue) => {
let delayedValue$;
if (!lastEmissionTime) {
// Don't delay the first emission.
delayedValue$ = of(currValue);
} else {
const delayBetweenValues = new Date().getTime() - lastEmissionTime;
// Wait for at least `MIN_DELAY`.
delayedValue$ =
delayBetweenValues > MIN_DELAY
? of(currValue)
: of(currValue).pipe(delay(MIN_DELAY - delayBetweenValues));
}
return delayedValue$.pipe(
// Remember time when the last value was reemited.
map((value) => [value, new Date().getTime()])
);
},
[null, null],
1 // We need to set concurrency to `1`.
),
map(([value]) => value)
)
现场演示:https://stackblitz.com/edit/rxjs-taeyzx?devtoolsheight=60&file=index.ts