LiveLoveApp logo

Subjects are Multicast

Multicast

A Subject, and all of its subclasses (or variants), are multicast. Observers to a Subject do not create individual executions of the underlying Observable. Rather, a Subject keeps track of the Observers and emits notifications to each Observer when the underlying Observable emits a notification.

Example

In this example we are going to create a new network request. We'll use the ajax operator to fetch JSON from a REST API.

import { ajax } from 'rxjs/ajax';
import { map } from 'rxjs/operators';

interface UserResponse {
  data: {
    id: number;
    email: string;
    first_name: string;
    last_name: string;
    avatar: string;
  };
}

const user = ajax
  .getJSON<UserResponse>('https://reqres.in/api/users/2')
  .pipe(map((response) => response.data));

Let's quickly review:

  • The UserResponse interface describes the shape of the response from our REST API.
  • Using the ajax operator we fetch the data and parse the JSON.
  • We map the data property from the response object.

Now, let's subscribe to our new observable a few times:

const sub1 = user.subscribe(console.log);
const sub2 = user.subscribe(console.log);

Upon inspection of the network requests that our application is creating we'll identify two identical requests. This is because multiple Observers to a cold observable create multiple independent executions.

Using a Subject

The problem we identified above is that our application is making multiple redundant network requests. To avoid this we can use a Subject to multicast the notifications from our Observable to multiple Observers.

import { Subject } from 'rxjs';

const userSubject = new Subject();
const sub1 = userSubject.subscribe(console.log);
const sub2 = userSubject.subscribe(console.log);

user.subscribe({
  next: (user) => userSubject.next(user),
  error: (e) => userSubject.error(e),
  complete: () => userSubject.complete()
});

Let's break this down:

  • First, we import the Subject class and new it up.
  • We then subscribe to the subject multiple times.
  • Finally, we subscribe to our user Observable and pass along the notifications to the userSubject.

Subjects are Observers

To simplify our example we can simply pass the userSubject as the Observer. A Subject is an Observer because it has the next(), error(), and complete() properties.

import { Subject } from 'rxjs';

const userSubject = new Subject();
const sub1 = userSubject.subscribe(console.log);
const sub2 = userSubject.subscribe(console.log);

user.subscribe(userSubject);