1
votes

From: https://www.learnrxjs.io/learn-rxjs/operators/combination/concat

Subscribe to observables in order as previous completes

???? You can think of concat like a line at a ATM, the next transaction (subscription) cannot start until the previous completes!

Given the above I'd expect the following example to log as 1, '2', '3', 4. When I run this I'm getting 1, 4, '3', '2'. Is there a way to ensure the piped logic has run before completing?

import { concat, of } from 'rxjs';
import { map } from 'rxjs/operators';

const o1o2 = of(console.log('1')).pipe(map(x => console.log(2)));
const o3 = () => console.log(3);
const o4 = of(console.log('4'));

concat(o1o2, of(o3()), o4).subscribe();

https://stackblitz.com/edit/rxjs-bqr9pr?file=index.ts


Edited:

In the above 1 and 4 were fired immediately when the lines were executed (before even hitting concat).

3 was fired because (of) creates a hot observable where logic happens before the observable returns. Similar scenario as above actually. As concat chains the observables before executing sequentially, so we see 3 logged. Defer is a way to make the observable cold.

2 was the only thing that was dependent on a subscription to log.

o4 = of(console.log('wut')).pipe(tap() => console.log(4))
also3 = defer() => {
    console.log(3)
    return of()
}
o3 = defer(() => {
    return of(console.log(3))
})
o2 = of(null).pipe(tap () => console.log(2))
o1 = of(null).pipe(tap () => console.log(1))

concat(o1, o2, o3, o4);

The below example would log wut, 1, 2, 3, 4

1

1 Answers

1
votes

Let's take this line-by-line:


const o1o2 = of(console.log('1')).pipe(map(x => console.log(2)));

When you call of on this line, you immediately evaluate console.log('1') and pass the result of the log function to of (the result of log is undefined).

This logs '1' to the console.


const o4 = of(console.log('4'));

Again, you are immediately evaluating console.log('4') and passing the result of that function, undefined, as the first argument to of

This logs '4' to the console.


concat(o1o2, of(o3()), o4).subscribe();

On this line, you are invoking o3 immediately and using the result of that function as the first argument for of. As o3 calls console.log(3) and returns its result, you are simply invoking of() with undefined.

This logs 3 to the console.


const o1o2 = of(console.log('1')).pipe(map(x => console.log(2)));

And we're now back to this line, which is, I think, the only one that is behaving as you were expecting because x => console.log(2) is a function, so it doesn't evaluate console.log until it's called. I don't know the RXJS library well, but since your second log call is wrapped in a function, it appears that concat is evaluating it while doing whatever it is that concat does.

This logs 2 to the console.