NOTE: I observed it rxjs 5.5.12, 6.5.4, 6.5.5.

You may think that below two codes gives same results where s0 and s1 are instances of BehaviorSubject.

Code-1

s1.pipe(
    withLatestFrom(s0)
).subscribe(([v1, v0]) => {
    console.log(v0, v1);
});

Code-2

s1.subscribe(v1 => {
    s0.pipe(take(1)).subscribe(v0 => {
        console.log(v0, v1);
    });
});

In general case, it's true. But, in very unique situation, these gives different results.
Here is test code for it.

const s0 = new BehaviorSubject('A');
const s1 = new BehaviorSubject('a');

setTimeout(() => s0.next('B'), 500);

let i = 0;
s0.pipe( /* Part-A */
    withLatestFrom(s1)
).subscribe(([v0, v1]) => {
    console.log('s0-pipe: ', v0, v1);
    s1.next(++i);
});

s1.pipe(
    withLatestFrom(s0)
).subscribe(([v1, v0]) => {
    console.log('s1-pipe: ', v0, v1);
});

s1.subscribe(v1 => {
    s0.pipe(take(1)).subscribe(v0 => {
        console.log('s1-sub: ', v0, v1);
    });
});

This gives following result.

s0-pipe:  A a
s1-pipe:  A 1
s1-sub:  A 1
s0-pipe:  B 1
s1-pipe:  A 2  <=
s1-sub:  B 2

Two very interesting results are observed. s1-pipe: A a and s1-sub: A a are not shown. And s0 value at second s1-pipe is not latest one!

To avoid this, I used below workaround at code Part-A.

s0.pipe(
    withLatestFrom(s1)
).subscribe(([v0, v1]) => {
    console.log('s0-pipe: ', v0, v1);
    setTimeout(() => s1.next(++i));
});

Then, it gives

s0-pipe:  A a
s1-pipe:  A a  <=
s1-sub:  A a  <=
s1-pipe:  A 1
s1-sub:  A 1
s0-pipe:  B 1
s1-pipe:  B 2  <=
s1-sub:  B 2

I think it's design of rxjs. One thing I can learn from above is that it's very risky using circular withLatestFrom at rxjs.

+ Recent posts