0

While implementing unsubscrive, I saw this answer.

I am tring the solution mentioned, but wanted to understand the following:

If I 'console.log(this.ngUnsubscribe)' before the 'this.ngUnsubscribe.next()' I see that the observers property of it is an array with 0 items.

Does it make sense? or am I missing something?

(before the subscribe I added the takeUntil(this.ngUnsubscribe) of-course)

----Update - added the code ----

imports:

import "rxjs/add/operator/takeUntil"
import {Subject} from "rxjs/Subject"

class:

export class CarComponent{

    @Input() id;

    car:Car;

    ngUnsubscibe:Subject<boolean> = new Subject();

    constructor(private carsService:CarService){}

    ngOnInit(){
       this.carsService.getDetails(this.id)
            .takeUntil(this.ngUnsubscibe)
            .subscribe((car) => {this.car = car}, 
                       (err) => console.log(err)
                       );
    }

    ngOnDestroy(){
         //HERE - in the log, the object has property 'observers' 
         //of type array which the length of it is 0
         console.log(this.ngUnsubscibe);
         this.ngUnsubscibe.next(true);
         this.ngUnsubscibe.complete();
    }

}
Batsheva
  • 659
  • 4
  • 13
  • 27

1 Answers1

1

Now I see the thing. You do not need to unsubscribe from Observables produced by the Angular's http service method calls. They automatically complete when you receive a value, because it represents an XHR call, which is obviously done by the time ngOnDestroy works. As it is done, the ngUnsubscribe Subject knows that the Observable it watches over is completed, so no need to unsubscribe it manually, thus the ngUnsubscribe unsubscribes from the source Observable to release resources. (and therefore the observers array becomes empty)

You only have to unsubscribe from the Observables that do not complete themselves. Try this code to see the difference:

export class CarComponent{

@Input() id;

car:Car;

ngUnsubscibe:Subject<boolean> = new Subject();

constructor(private carsService:CarService){}

ngOnInit(){
   this.carsService.getDetails(this.id)
        .takeUntil(this.ngUnsubscibe)
        .subscribe((car) => {this.car = car}, 
                   (err) => console.log(err)
                   );
    Observable.fromEvent(document.body, 'click').takeUntil(this.ngUnsubscribe)
.subscribe(console.log)
     // so this is an Observable which listens to document clicks. As there 
//is no way to determine that a certain click was in fact the last, 
//we have to terminate it manually
}

ngOnDestroy(){
     //HERE - in the log, the object has property 'observers', 
     // and NOW it has length 1, as it contains the click listener Observable
     console.log(this.ngUnsubscibe);
     this.ngUnsubscibe.next(true);
     this.ngUnsubscibe.complete();
    }
}

So, once more - no need to unsubscribe from http call Observables, as they are automatically completed upon receiving data. A common example of Observable in Angular which needs to be terminated manually is a subscription to a form's valueChanges observable, any Observables that you wrote to transport data from one component/service to another, and maybe store Observables like ngrx stuff, otherwise you may end up with a bunch of "zombie" Subscriptions, potentially resulting in a memory leak.

Armen Vardanyan
  • 3,214
  • 1
  • 13
  • 34