Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In angular2, is it possible to get a count of subscribers to an observable?

Tags:

angular

rxjs

I imagine it would be possible to keep subscribing to an observable and forget to unsubscribe. I suspect this is happening in my application. Does the observable have a property that could give me a count of the subscribers hanging off it?

like image 779
FeeFiFoFum Avatar asked Jul 28 '16 04:07

FeeFiFoFum


1 Answers

While it is absolutely possible to forget to unsubscribe, and the leaks have consequences ranging from test runners that never end to memory leaks, angular2 has some tools and common patterns to manage its life-cycle.

angular2 provides a simple way not to forget. The simplest way, when used in templates, is to simply use the async pipe which will automatically subscribe and unsubscribe for you.

Otherwise, when you use the .subscribe() method, it returns a subscription. A common practice would be to capture injected dependencies in the constructor, make the necessary subscriptions of a component within ngOnInit and unsubscribe from within ngOnDestroy.

Sometimes, you will be subscribing to multiple observables. RxJS provides the class Rx.Subscription to group subscriptions together. It can be used in the following way:

const incomeSubscription = income$.subscribe(x => console.log(x));
const expensesSubscription = expenses$.subscribe(x => console.log(x));

const subscription = new Rx.Subscription();
subscription.add(incomeSubscription);
subscription.add(expensesSubscription);

Now calling subscription.unsubscribe() will unsubscribe any subscription still active.

Finally, it is important to understand that RxJS streams are unicast by default (unlike promises which always cache the results and are only multicast). This means in practice that each subscription actually becomes a new rx stream. In the case of "cold" observables like Http.get() for example, that each subscription will actually generate the data from scratch. So in the mentioned case with Http.get(), you will make a HTTP call for each subscription (or instance that uses the pipe async in the template).

This means that it is good practice to:

  • Only use the async pipe in a container style component, and have dumb presentational components that know nothing of RxJS. This helps to only subscribe at the container level

  • If sharing data among subscribers to use an operator like .refCount() in some cases or Subjects in others. This makes the stream multicast and subscribers share the same stream rather than each have their own

  • With angular v4+, it has become a good practice to use the | async in combination with as secondaryName (stream$ | async as streamData) so within the container component, if you use the values of an observable more than once, you don't subscribe multiple times to the observable

like image 161
Ben Dadsetan Avatar answered Oct 13 '22 00:10

Ben Dadsetan