Reactive-Extensions / RxJS

The Reactive Extensions for JavaScript
http://reactivex.io
Other
19.49k stars 2.1k forks source link

Is that a bug which using `startWith` before `withLatestFrom` ? #1509

Open Qquanwei opened 6 years ago

Qquanwei commented 6 years ago

When I only using startWith, it's works fine for me

const rx = require('rxjs')

const test2$ = rx.Observable
                 .interval(50)
                 .mapTo('test2')
                 .take(10)

const test1$ = rx.Observable
                 .interval(100)
                 .take(5)
                 .startWith(-1)
 //                .withLatestFrom(test2$)

test1$.subscribe((a) => {
  console.log(a)
})

output

-1
0
1
2
3
4

But when uncomment

...
const test1$ = rx.Observable
                 .interval(100)
                 .take(5)
                 .startWith(-1)
                 .withLatestFrom(test2$)

test1$.subscribe((a) => {
  console.log(a)
})

It's output

[ 0, 'test2' ]
[ 1, 'test2' ]
[ 2, 'test2' ]
[ 3, 'test2' ]
[ 4, 'test2' ]

It's no sense with that result, isn't ?

whiteinge commented 6 years ago

This is expected behavior. withLatestFrom needs a value from both sides before it will start emitting. The sequence above goes:

  1. startWith emits immediately but withLatestFrom only has a cached "left" value and so doesn't emit.
  2. The "right" side emits at 50 ms and that value is also cached in the withLatestFrom, however it doesn't emit because it only emits when the "left" side emits.
  3. The "left" side emits at 100 ms and withLatestFrom finally emits with the new "left" value and the most recent "right" value.

In other words: values on the "left" side will be ignored until the "right" side emits.


Side-note: It looks like you're using Rx 5 so you want that repo instead. This repo is for Rx 4 which is in maintenance-only mode. That said, I expect the answer above will apply to both versions.

If you're interested to read more, and if you're in a position where you can't ensure the "right" will emit before the "left", there's a discussion and solution about using both combineLatest and withLatestFrom to avoid this behavior on StackOverflow. I ended up making a custom operator, waitLatestFrom -- although it's for Rx 4 it should be easy to adapt to Rx 5.