Service subscription is quite common in Angular development. However, if you are implementing incorrectly, it could cause the memory leak to be happened in your application. So, it is really important for you to know a proper way to do a service subscription in your Angular components. In this post, I would like to share one of the methods that I usually use when I work on the Angular project.

Assumption: Let’s say in your Angular project, you have a ComponentA that is going to subscribe to an event from a ServiceX. Let’s say this event is called onSomethingChanged.

Example of an event declaration in your ServiceX:

private _onSomethingChanged = new Subject<T>();
public onSomethingChanged = this._onSomethingChanged.asObservable();

Here are what you need to do in your ComponentA

Import the following RxJS modules. We’re going to use ReplaySubject and takeUntil pipe.

import { ReplaySubject } from 'rxjs/ReplaySubject';
import { takeUntil } from 'rxjs/operators';

Your ComponentA needs to implement both OnInit and OnDestroy.

@Component({
  selector: '...',
  templateUrl: '...',
  styleUrls: ['...']
})
export class ComponentA implements OnInit, OnDestroy {
    ...
}

Add this declaration on top of your ComponentA constructor.

private destroyed$: ReplaySubject<boolean> = new ReplaySubject(1);

Put this in your ngOnDestroy() function.

ngOnDestroy() {
  this.destroyed$.next(true);
  this.destroyed$.complete();
}

Inject your ServiceX into your ComponentA constructor.

constructor(
  private serviceX: ServiceX
) { }

Finally, you can subscribe to onSomethingChanged event from your ServiceX in your ngOnInit() function.

ngOnInit() {
  this.serviceX.onSomethingChanged
    .pipe(takeUntil(this.destroyed$))
    .subscribe(result => {
        console.log(result);
  });
}

This assumes you want to listen to onSomethingChanged event from the beginning of your ComponentA is loaded. So, whenever your ComponentA is unloaded, the subscription to the event will be destroyed automatically.

Subject vs. BehaviorSubject vs. ReplaySubject

SubjectA subscriber will only get published values that were emitted after the subscription.
BehaviorSubjectThe last value is cached. A subscriber will get the latest value upon initial subscription. BehaviorSubject requires an initial value to be defined.
ReplaySubjectIt can cache up to a specified number of published values or emissions. Any subscriber will get all the cached values upon subscription.

Initializing ReplaySubject with a buffer size of 1 actually computes a similar behavior as BehaviorSubject as the last value is always cached, so it acts like a value changing over time. The only difference is that, it does not need for null checking compared to the BehaviorSubject which requires the subscriber to perform null checking if the initial value is set to null.