Observables are Unicast
Unicast vs Multicast
We need to understand a key distinction between a Subject
and an Observable
.
By default, an Observable
is unicast.
This means that each Observer owns a separate execution of the Observable
.
On the other hand, a Subject
and its subclasses (or variants) are multicast.
This means that when a Subject
receives a new Observer it does not invoke a new execution for the production of values.
Rather, each Observer receives the same produced value(s).
Hot vs. Cold Observable
Before we get into why this matters, we need to first quickly recap the distinction between a hot and a cold Observable:
- A cold Observable starts to produce values (events, iterators, objects, whatever) upon a new Observer.
- A hot Observable produces values outside of the Observable, and the Observer begins to receive next notifications of those values until completion or error.
If you are an Angular developer you likely know that the HttpClient
is a cold Observable.
It is only upon subscribing that the request is sent, and subsequently, the response's next notification is emitted asynchronously containing the response (or body of the response).
Why does this matter?
Most importantly, this matters when the execution of producing values within a cold observable is expensive.
Hypothetically, lets say that the cold observable is making a network request. If I subscribe to the Observable three times then the cold Observable will create three network requests.
Example
Let's look at an example of this:
import { Observable } from "rxjs";
/* create a new observable, providing the observer. */
const observable: Observable<number> = new Observable((observer) => {
console.log('%cNew subscription created', 'background: #222; color: #bada55');
let i = 0;
const interval = setInterval(() => {
observer.next(i++);
}, 1000);
return () => {
clearInterval(interval);
};
});
/* Each subscription receives a copy of Observer. */
const subscription = observable.subscribe((value) =>
console.log('First subscription', value)
);
setTimeout(
() =>
subscription.add(
observable.subscribe((value) => console.log('Second subscription', value))
),
500
);
/* Unsubscribe after 5 seconds. */
setTimeout(() => {
subscription.unsubscribe();
}, 5000);
When you execute this code you'll notice:
- The console will log out
New subscription created
twice. Once for each Observer. - We then receive 4 next notifications.
- Finally, we unsubscribe after 5 seconds.