Mastering RxJS Join Creation Operators (Combination Operators)

Nandeep Barochiya
4 min readMay 20, 2024

--

Reactive programming has become a cornerstone in modern web development, providing a robust way to handle asynchronous data streams. RxJS, or Reactive Extensions for JavaScript, is one of the most popular libraries for implementing reactive programming in JavaScript. Among its many features, creation operators stand out as essential tools for generating observable streams. In this section, we’ll explore the various RxJS join creation operators, how they work, and practical use cases for each.

RxJS

What are RxJS Join Creation Operators?

These operators create new Observables from multiple source Observables, allowing developers to combine data streams in various ways. Understanding these operators is fundamental to leveraging the full power of RxJS.

List of Join Creation Operators

(Note:⭐ — commonly used”)

  • combineLatest: It combines the latest values from multiple Observables into a single Observable.
  • concat: It concatenates multiple Observables into a single Observable, emitting values in the order they are received.
  • forkJoin: It combines multiple Observables into a single Observable, emitting an array of values when all Observables are complete.
  • merge: It combines multiple Observables into a single Observable, emitting values as they are received.
  • partition: It splits an Observable into two Observables based on a predicate function.
  • race: It returns an Observable that emits the first value emitted by any of the source Observables.
  • zip: It combines multiple Observables into a single Observable by pairing the values from each Observable together based on their order.

Now we will review each Join Creation Operator one by one and learn through examples.

combineLatest

combineLatest combines the latest values from multiple Observables into a single Observable.

This operator is useful when you need to combine the latest values from multiple data streams. It’s particularly useful in scenarios where you need to react to changes in multiple data sources simultaneously.

import { combineLatest } from 'rxjs';

const obs1 = of(1, 2, 3);
const obs2 = of('a', 'b', 'c');

combineLatest(obs1, obs2).subscribe(([num, letter]) => {
console.log(`Number: ${num}, Letter: ${letter}`);
});

// Output:
// Number: 1, Letter: a
// Number: 2, Letter: b
// Number: 3, Letter: c

concat

concat concatenates multiple Observables into a single Observable, emitting values in the order they are received.

This operator is useful when you need to concatenate multiple data streams in a specific order. It’s particularly useful in scenarios where you need to process data streams sequentially.

import { concat } from 'rxjs';

const obs1 = of(1, 2, 3);
const obs2 = of(4, 5, 6);

concat(obs1, obs2).subscribe(val => {
console.log(val);
});

// Output:
// 1
// 2
// 3
// 4
// 5
// 6

forkJoin

forkJoincombines multiple Observables into a single Observable, emitting an array of values when all Observables are complete.

This operator is useful when you need to combine multiple data streams and wait for all of them to complete before processing the results. It’s particularly useful in scenarios where you need to perform multiple asynchronous operations in parallel.

import { forkJoin } from 'rxjs';

const obs1 = of(1, 2, 3);
const obs2 = of('a', 'b', 'c');

forkJoin(obs1, obs2).subscribe(([nums, letters]) => {
console.log(`Numbers: ${nums}, Letters: ${letters}`);
});

// Output:
// Numbers: 1,2,3, Letters: a,b,c

merge

merge combines multiple Observables into a single Observable, emitting values as they are received.

This operator is useful when you need to combine multiple data streams and emit values as soon as they are received. It’s particularly useful in scenarios where you need to process data streams concurrently.

import { merge } from 'rxjs';

const obs1 = of(1, 2, 3);
const obs2 = of(4, 5, 6);

merge(obs1, obs2).subscribe(val => {
console.log(val);
});

// Output:
// 1
// 4
// 2
// 5
// 3
// 6

partition

partition splits an Observable into two Observables based on a predicate function.

This operator is useful when you need to split a data stream into two separate streams based on a condition. It’s particularly useful in scenarios where you need to process data differently based on certain criteria.

import { of, partition } from 'rxjs';

const source = of(1, 2, 3, 4, 5);

const [even$, odd$] = partition(source, value => value % 2 === 0);

even$.subscribe(value => console.log(`Even: ${value}`));
odd$.subscribe(value => console.log(`Odd: ${value}`));

// Output:
// Even: 2
// Odd: 1
// Even: 4
// Odd: 3
// Even: 5

race

race returns an Observable that emits the first value emitted by any of the source Observables.

This operator is useful when you need to wait for the first value from multiple data streams and then stop processing the other streams. It’s particularly useful in scenarios where you need to perform multiple asynchronous operations and only care about the first result.

import { of, race } from 'rxjs';

const obs1 = of('Hello').pipe(delay(1000));
const obs2 = of('World').pipe(delay(500));

race(obs1, obs2).subscribe(value => {
console.log(value);
});

// Output:
// World

zip

zip combines multiple Observables into a single Observable by pairing the values from each Observable together based on their order.

This operator is useful when you need to combine multiple data streams and emit values based on their order. It’s particularly useful in scenarios where you need to perform operations on multiple data streams simultaneously

import { of, zip, map } from 'rxjs';

const age$ = of(27, 25, 29);
const name$ = of('Foo', 'Bar', 'Beer');
const isDev$ = of(true, true, false);

zip(age$, name$, isDev$).pipe(
map(([age, name, isDev]) => ({ age, name, isDev }))
)
.subscribe(x => console.log(x));

// Outputs
// { age: 27, name: 'Foo', isDev: true }
// { age: 25, name: 'Bar', isDev: true }
// { age: 29, name: 'Beer', isDev: false }

In conclusion, mastering RxJS join creation operators is crucial for any developer working with asynchronous data streams. These operators — combineLatest, concat, forkJoin, merge, partition, race, and zip — each provide unique ways to combine and manipulate multiple Observables, enabling more efficient and responsive data handling in your applications. By understanding and effectively using these operators, you can harness the full power of reactive programming with RxJS, creating robust, maintainable, and highly responsive web applications.

Happy coding!

--

--