Multicasting Operators in RxJS: A Comprehensive Guide

Nandeep Barochiya
5 min readMay 28, 2024

--

RxJS provides powerful tools for handling asynchronous data streams, and multicasting operators are among the most useful. These operators allow multiple observers to subscribe to a single observable, enabling efficient data sharing and reducing resource usage. In this guide, we’ll explore the key multicasting operators: multicast, publish, publishBehavior, publishLast, publishReplay, and share. Through real-time examples, we'll demonstrate how to use these operators effectively in your reactive programming projects.

RxJS

List of Multicasting Operators

(Note: “⭐ — commonly used”)

  • multicast: Allows you to create a ConnectableObservable, which waits until its connect method is called before it begins emitting items to those observers who have subscribed to it.
  • publish: Shares a single subscription to the underlying Observable and starts emitting items to subscribers when the connect method is called. It can be thought of as a variant of multicast with a Subject.
  • publishBehavior: Similar to publish, but it emits the most recent item observed by the underlying Observable (or a seed/default value) to new subscribers.
  • publishLast: Shares a single subscription to the underlying Observable and emits only the last value (or the last few values) emitted by the source Observable to any subsequent subscribers.
  • publishReplay: Shares a single subscription to the underlying Observable and replays all of the items emitted by that Observable to any new subscribers.
  • share: Shares a single subscription to the underlying Observable among multiple subscribers. It is a shorthand for multicast with a refCount, making it suitable for hot Observables that should be shared among multiple subscribers.

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

multicast

Imagine you’re developing a real-time stock price application where multiple components need to display the latest stock prices. Instead of each component subscribing to the stock price service separately, which would create redundant network requests, you can use multicast to share a single subscription among all components.

import { Subject, interval } from 'rxjs';
import { multicast, tap, take } from 'rxjs/operators';

// Simulated observable for stock prices
const stockPrice$ = interval(1000).pipe(
take(3),
tap(price => console.log(`Fetching stock price: ${price}`))
);

const subject = new Subject();
const multicasted$ = stockPrice$.pipe(multicast(subject));

multicasted$.subscribe(price => console.log(`Component 1: ${price}`));
multicasted$.subscribe(price => console.log(`Component 2: ${price}`));

// Start the multicasting
multicasted$.connect();

/* Output
Fetching stock price: 0
Component 1: 0
Component 2: 0
Fetching stock price: 1
Component 1: 1
Component 2: 1
Fetching stock price: 2
Component 1: 2
Component 2: 2
*/

The multicast operator shares the subscription to stockPrice$ among multiple subscribers, ensuring that the stock price is fetched only once per interval. Both components receive the same price updates.

publish

You have a live news feed that updates every few seconds. You want different sections of your application to display the latest news without making separate requests for each section.

import { interval } from 'rxjs';
import { publish, tap, take } from 'rxjs/operators';

// Simulated observable for news feed
const newsFeed$ = interval(1000).pipe(
take(3),
tap(news => console.log(`Fetching news: ${news}`))
);

const published$ = newsFeed$.pipe(publish());

published$.subscribe(news => console.log(`Section 1: ${news}`));
published$.subscribe(news => console.log(`Section 2: ${news}`));

// Start the multicasting
published$.connect();

/* Output
Fetching news: 0
Section 1: 0
Section 2: 0
Fetching news: 1
Section 1: 1
Section 2: 1
Fetching news: 2
Section 1: 2
Section 2: 2
*/

publishBehavior

In a chat application, you want new users to see the last message sent in the chat immediately upon joining.

import { interval } from 'rxjs';
import { publishBehavior, tap, take } from 'rxjs/operators';

// Simulated observable for chat messages
const chatMessages$ = interval(1000).pipe(
take(3),
tap(message => console.log(`New message: ${message}`))
);

const published$ = chatMessages$.pipe(publishBehavior('No new messages'));

published$.subscribe(message => console.log(`User 1: ${message}`));
published$.connect();
setTimeout(() => published$.subscribe(message => console.log(`User 2: ${message}`)), 1500);

/* Output
User 1: No new messages
New message: 0
User 1: 0
User 2: 0
New message: 1
User 1: 1
User 2: 1
New message: 2
User 1: 2
User 2: 2
*/

The publishBehavior operator provides an initial value so new subscribers receive the last emitted value immediately upon subscription.

publishLast

You have a batch processing system where you want to notify multiple services of the final result once all tasks are completed.

import { interval } from 'rxjs';
import { publishLast, tap, take } from 'rxjs/operators';

// Simulated observable for batch processing
const batchProcess$ = interval(1000).pipe(
take(3),
tap(process => console.log(`Processing: ${process}`))
);

const published$ = batchProcess$.pipe(publishLast());

published$.subscribe(result => console.log(`Service 1: ${result}`));
published$.connect();
setTimeout(() => published$.subscribe(result => console.log(`Service 2: ${result}`)), 4000);

/*
Processing: 0
Processing: 1
Processing: 2
Service 1: 2
Service 2: 2
*/

The publishLast operator ensures that the final value of the observable is shared with all subscribers after the observable completes.

publishReplay

In an online learning platform, you want new students to be able to see the last few chat messages when they join a live class.

import { interval } from 'rxjs';
import { publishReplay, tap, take } from 'rxjs/operators';

// Simulated observable for chat messages
const chatMessages$ = interval(1000).pipe(
take(3),
tap(message => console.log(`New message: ${message}`))
);

const published$ = chatMessages$.pipe(publishReplay(2));

published$.subscribe(message => console.log(`Student 1: ${message}`));
published$.connect();
setTimeout(() => published$.subscribe(message => console.log(`Student 2: ${message}`)), 4000);

/* Output
New message: 0
Student 1: 0
New message: 1
Student 1: 1
New message: 2
Student 1: 2
Student 2: 1
Student 2: 2
*/

The publishReplay operator replays the last two values to new subscribers, ensuring they catch up on recent emissions.

share

You have a live sports score update observable that multiple components in your application need to access. You want to ensure that each score update is fetched only once, but all components can display the latest score.

import { interval } from 'rxjs';
import { share, tap, take } from 'rxjs/operators';

// Simulated observable for live sports scores
const liveScores$ = interval(1000).pipe(
take(3),
tap(score => console.log(`Fetching score: ${score}`))
);

const shared$ = liveScores$.pipe(share());

shared$.subscribe(score => console.log(`Component 1: ${score}`));
setTimeout(() => shared$.subscribe(score => console.log(`Component 2: ${score}`)), 1500);

/* Output
Fetching score: 0
Component 1: 0
Fetching score: 1
Component 1: 1
Component 2: 1
Fetching score: 2
Component 1: 2
Component 2: 2
*/

Conclusion

In this guide, we explored the powerful multicasting operators in RxJS: multicast, publish, publishBehavior, publishLast, publishReplay, and share. These operators enable efficient data sharing among multiple subscribers, reducing resource usage and ensuring consistent data flow. By mastering these operators, you can build more efficient and responsive reactive applications. We hope this comprehensive guide helps you leverage the full potential of RxJS multicasting operators in your projects.

Happy coding!

--

--