Reputation: 35
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
Upvotes: 1
Views: 623
Reputation: 25810
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.
Upvotes: 1