When and How to Unsubscribe

For preventing memory leaks, after the Observable completes, all of the subscribers should unsubscribe an Observable and free the allocated memory. Some operators won't work if the observable does not complete, e.g. concatMap will wait for Observables to complete before switching to the next one. Fortunately we need not unsubscribe explicitly every Observable.

  • Generally speaking, we complete Observables by calling
    1. Observable.onComplete()
    2. Observable.onError()
    3. Subscription.unsubscribe() (subscription = observable.subscribe(...))
    methods.

  • Execute a HTTP request by HTTPClient: need not unsubscribe explicity. The return value of a HTTP request is a cold Observable which emits data only once and then RxJS call OnCompleted() method automatically.
  • Use Angular AsyncPipe: need not unsubscribe explicity.
  • some RxJS operators, e.g. take, takeUntil, takeWhite, first : need not unsubscribe explicity.
  • some RXJS operators, e.g. Subject, BehaviorSubject, AsyncSubject, ReplaySubject: need unsubscribe
  • Unsubscribe() method is often called in ngDestroy hook. For preventing forgetting call this method before destroying the component, we can add a class decorator for component.
    import { Component, OnInit, OnDestroy } from '@angular/core';
    import { Subscription, interval, Subject } from 'rxjs';
    
    function AutoUnsubscribe() {
      return function (obj: Function) {
        const orig = obj.prototype.ngOnDestroy;
        obj.prototype.ngOnDestroy = function () {
          console.log('automatic unsubscribe component destroyed');
          // tslint:disable-next-line: forin
          for (const prop in this) {
            const property = this[prop];
            if (typeof property.unsubscribe === 'function') {
              property.unsubscribe();
            }
          }
          orig.apply();
        };
      };
    }
    
    @Component({
      selector: 'app-hwo-to-unsubscribe',
      template: `<button (click)="unsubscribe()">unsubscribe</button>`,
    })
    
    @AutoUnsubscribe()
    export class AutomaticUnsubscribeComponent implements OnInit, OnDestroy {
          ...
    }