rxjsobservablecombinelatest

RxJS combineAll Operator, explanation


I'm trying to understand how does the combineAll operator work. I'm using the following example from the official documentation:

import { take, map, combineAll } from 'rxjs/operators';
import { interval } from 'rxjs';

const source$ = interval(1000).pipe(take(2));

const example$ = source$.pipe(
  map(val =>
    interval(1000).pipe(
      map(i => `Result (${val}): ${i}`),
      take(5)
    )
  )
);

example$
  .pipe(combineAll())
  .subscribe(console.log);

The output is then :

["Result (0): 0", "Result (1): 0"]
["Result (0): 1", "Result (1): 0"]
["Result (0): 1", "Result (1): 1"]
["Result (0): 2", "Result (1): 1"]
["Result (0): 2", "Result (1): 2"]
["Result (0): 3", "Result (1): 2"]
["Result (0): 3", "Result (1): 3"]
["Result (0): 4", "Result (1): 3"]
["Result (0): 4", "Result (1): 4"]

Trying to figure why, I made this simple scheme:

combineAll Scheme

From the documentation, I read that each time any of the inner Observable emits a value, then this emitted value is combined by the last value of all the other inner observables.

In the scheme above, we can see that 10 values are emitted during time by the inner Observables, so I was expecting to get an output with 10 values over the time, but it's 9.

Also, in the first line of the output :

["Result (0): 0", "Result (1): 0"]) 

Does the 0 of 'Result (1): 0' correspond to a null value? Because Observable 'inner 2' has not yet emitted anything?

To finish here is what I was expecting as output :

["Result (0): 0", "Result (1): 0"]
["Result (0): 1", "Result (1): 0"]
["Result (0): 1", "Result (1): 0"]
["Result (0): 2", "Result (1): 0"]
["Result (0): 2", "Result (1): 1"]
["Result (0): 3", "Result (1): 1"]
["Result (0): 3", "Result (1): 2"]
["Result (0): 4", "Result (1): 2"]
["Result (0): 4", "Result (1): 3"]
["Result (0): 4", "Result (1): 4"]

It's obviously wrong but I don't find my mistake, could someone explain?


Solution

  • Consider that combineAll:

    flattens an Observable-of-Observables by applying combineLatest when the Observable-of-Observables completes.

    And that combineLatest;

    will actually wait for all input Observables to emit at least once.

    So the first emission from the combineAll observable that includes the first value of the "Inner 1" observable is not going to happen until the "Inner 2" observable emits its first value. So there will only be nine emissions - not ten.