Operators combination

There are many operators out there that allows you to combine the values from 2 or more source, they act a bit differently though and its important to know the difference.

combineLatest

The signature on this one is:

import { combineLatest } from 'rxjs';

combineLatest([ source_1, ... source_n])
1
2
3
import { interval } from 'rxjs';
import { map, take } from 'rxjs/operators';

let source1 = interval(100).pipe(
  map( val => "source1 " + val ),
  take(5)
);

let source2 = interval(50).pipe(
  map( val => "source2 " + val),
  take(2)
);

let stream$ = combineLatest(
  source1,
  source2
);

stream$.subscribe(data => console.log(data));

// emits source1: 0, source2 : 0 | source1 : 0, source2 : 1 | source1 : 1, source2 : 1, etc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

What this does is to essentially take the latest response from each source and return it as an array of x number of elements. One element per source.

As you can see source2 stops emitting after 2 values but is able to keep sending the latest emitted.

Business case

The business case is when you are interested in the very latest from each source and past values is of less interest, and of course you have more than one source that you want to combine.

concat

The signature is :

Observable([ source_1,... sournce_n ])
1

Looking at the following data, it's easy to think that it should care when data is emitted:

import { interval, concat } from 'rxjs';

let source1 = interval(100).pipe(
  map( val => "source1 " + val ),
  take(5)
);

let source2 = interval(50).pipe(
  map( val => "source2 " + val ),
  take(2)
);


let stream$ = concat(
  source1,
  source2
);

stream$.subscribe( data => console.log('Concat ' + data));

// source1 : 0, source1 : 1, source1 : 2, source1 : 3, source1 : 4
// source2 : 0, source2 : 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

The result however is that the resulting observable takes all the values from the first source and emits those first then it takes all the values from source 2, so order in which the source go into concat() operator matters.

So if you have a case where a source somehow should be prioritized then this is the operator for you.

merge

This operator enables you two merge several streams into one.

import { merge } from 'rxjs';

let merged$ = merge(
  Rx.Observable.of(1).delay(500),
  Rx.Observable.of(3,2,5)
);

let observer = {
  next : data => console.log(data)
}

merged$.subscribe(observer);
1
2
3
4
5
6
7
8
9
10
11
12

Point with is operator is to combine several streams and as you can see above any time operators such as delay() is respected.

zip

import { zip, of } from 'rxjs';

let stream$ = zip(
  Promise.resolve(1),
  of(2,3,4),
  of(7)
);


stream$.subscribe(observer);
1
2
3
4
5
6
7
8
9
10

Gives us 1,2,7

Let's look at another example

import { zip, of } from 'rxjs';

let stream$ = zip(
  of(1,5),
  of(2,3,4),
  of(7,9)
);

stream$.subscribe(observer);
1
2
3
4
5
6
7
8
9

Gives us 1,2,7 and 5,3,9 so it joins values on column basis. It will act on the least common denominator which in this case is 2. The 4 is ignored in the 2,3,4 sequence. As you can see from the first example it's also possible to mix different async concepts such as Promises with Observables because interval conversion happens.

Business case

If you really care about what different sources emitted at a certain position. Let's say the 2nd response from all your sources then zip() is your operator.