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
thedata
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 theuserSubject
.
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);