I want to achieve the following behavior in RxJS but could not find a way using the available operators:
- Stream A: Generated by a continuous stream of events (e.g. browser scroll)
- Stream B: Generated by another arbitrary event (e.g. some kind of user input)
- When B emits a value, I want to pause the processing of A, until a specified amount of time has passed. All values emitted by A in this timeframe are thrown away.
- When B emits another value during this interval, the interval is reset.
- After the interval has passed, the emitted values of A are no longer filtered.
// Example usage.
streamA$
.pipe(
unknownOperator(streamB$, 800),
tap(val => doSomething(val))
)
// Output: E.g. [event1, event2, <skips processing because streamB$ emitted>, event10, ...]
// Operator API.
const unknownOperator = (pauseProcessingWhenEmits: Observable<any>, pauseIntervalInMs: number) => ...
I thought that throttle could be used for this use case, however it will not let any emission through, until B has emitted for the first time (which might be never!).
streamA$
.pipe(
// If B does not emit, this never lets any emission of A pass through!
throttle(() => streamB$.pipe(delay(800)), {leading: false}),
tap(val => doSomething(val))
)
An easy hack would be to e.g. subscribe manually to B, store the timestamp when a value was emitted in the Angular component and then filter until the specified time has passed:
(obviously goes against the side-effect avoidance of a reactive framework)
streamB$
.pipe(
tap(() => this.timestamp = Date.now())
).subscribe()
streamA$
.pipe(
filter(() => Date.now() - this.timestamp > 800),
tap(val => doSomething(val))
)
I wanted to check with the experts here if somebody knows an operator (combination) that does this without introducing side-effects, before I build my own custom operator :)