Search code examples
javascriptrxjsrxjs5requestanimationframe

How can I use RxJS to generate a requestAnimationFrame loop?


My goal is to create an animation loop à la requestAnimationFrame so that I could do something like this:

animationObservable.subscribe(() =>
{
    // drawing code here
});

I tried this code as a basic test:

let x = 0;

Rx.Observable
    .of(0)
    .repeat(Rx.Scheduler.animationFrame)
    .takeUntil(Rx.Observable.timer(1000))
    .subscribe(() => console.log(x++));

Here is a JSFiddle but I'm not liable for any browser crashes from running this.

I expected this to log the numbers from 0 to approximately 60 (because that is my monitor's refresh rate) over 1 second. Instead, it rapidly logs numbers (much faster than requestAnimationFrame would), begins to cause the page to lag, and finally overflows the stack around 10000 and several seconds later.

Why does the animationFrame scheduler behave this way, and what is the correct way to run an animation loop with RxJS?


Solution

  • It's because the default behaviour of Observable.of is to emit immediately.

    To change this behaviour, you should specify the Scheduler when calling Observable.of:

    let x = 0;
    
    Rx.Observable
        .of(0, Rx.Scheduler.animationFrame)
        .repeat()
        .takeUntil(Rx.Observable.timer(1000))
        .subscribe(() => console.log(x++));
    <script src="https://npmcdn.com/@reactivex/[email protected]/dist/global/Rx.min.js"></script>

    Or, more simply, replace the of and repeat operators with:

    Observable.interval(0, Rx.Scheduler.animationFrame)