The RxJS concatAll flattens a higher-order Observable by concatenating all the values from inner Observables in order. This means all of one inner Observable’s values are considered before the next
RxJS concatAll flattens in sequence
Let us have a look at a basic example with a higher-order Observable containing two Observables:
it('handles inner observables in sequence', () => {
createTestScheduler().run((helpers) => {
const { expectObservable, cold } = helpers;
const source$ = of(
cold('--aa|', { a: 'a' }),
cold('bb|', { b: 'b' })
);
const result$ = source$.pipe(concatAll());
expectObservable(result$).toBe(
'--aabb|',
{ a: 'a', b: 'b' }
);
});
});
First, the values of the first inner Observable are emitted (although they would be emitted later than the ones from the second Observable). Important, one inner Observable has to complete before the next one is subscribed to.
So, concatAll is equal to mergeAll with concurrency set to 1. It is also implemented like that.
One error in an inner Observable stops everything
Now, if in the above example the first inner Observable emitting the a’s would throw an error, we would never see a b in the final Observable:
it('stops on error', () => {
createTestScheduler().run((helpers) => {
const { expectObservable, cold } = helpers;
const source$ = of(
cold('--aa#', { a: 'a' }),
cold('bb|', { b: 'b' })
);
const result$ = source$.pipe(concatAll());
expectObservable(result$).toBe(
'--aa#',
{ a: 'a', b: 'b' }
);
});
});
Watch out for memory issues
Merge internally uses a buffer to put values in a waiting state when the concurrency limit is too low:
Hence, if the source Observable emits quickly (and endlessly) while the inner Observable is slower in handling values, we could run into memory issues.
Exercise for the RxJS concatAll operator 💪
Use concatAll to spawn snakes all over the page. This is a little “game” for which you will find a starter html on GitHub. The final result should look somewhat like this:
This post is part of the RxJS mastery series. As always the code examples can be found on GitHub.