Search code examples
javascriptrxjsreactivex

Queue events to fire every 350ms with RxJS


I have a keyboard event that causes an animation to play. It's possible for the user to produce more events than the rate that the animation plays so I want to create a queue that will eventually empty firing one by one after a certain amount of delay.

Desired marble diagram:

=================================================

user:    START|a-b-c-----------------------------

result:  START|-350ms--a--350ms--b--350ms--c-----

=================================================

The user fires 3 events rapidly (a b c). After event a fires, 350ms timer starts. After that timer is finishes, the result fires a and starts another 350ms timer. After that timer is done it fires b. Basically, if a timer is in progress, I want to add it to the queue and emit it later. The rate cannot exceed 350ms and I want every event.

I want to throttle the output of the events to 350ms but I don't want to use the throttle operator because I don't want to loose any events (I want a, b, and c to fire).

A Javascript RxJS solution is preferred but I'll accept any answer with Rx operators in any language.


Solution

  • This seems to do the trick:

    import { fromEvent, concat, timer } from 'rxjs';
    import { tap, concatMap, filter } from 'rxjs/operators';
    
    fromEvent(document, 'keypress')
    .pipe(
      filter((e: KeyboardEvent) => e.code === 'Space'),
      concatMap(() => timer(350))
    ).subscribe(console.log)
    

    Blitz


    Edit: The concat() operator is redundant. Removed.