There has been a lot discussion about when and how to unsubscribe and that subscriptions shouldn't leak outside of a service. I have read many articles about this matter and I think I understood some parts, but what I'm missing in the writeups and tutorials if found, is what to do with the "new subscription pattern" we created.
So I will first explain from which concept I'm talking and put the question afterwards.
CONCEPT:
// some.component.ts (extremely simplified)
this.someSub = this.backendService.someStuff.subscribe(...);
ngOnDestroy() {
this.someSub.unsubscribe(); // I hope we agree that it is best practice to unsubscribe here, but anyway this is not the question
}
// backend.service.ts
export class BackendService {
private _someStuff = new BehaviorSubject<any>(null);
readonly someStuff = this._someStuff.asObservable();
constructor(http: HttpClient) { }
getStuff() {
this.http.get('...').subscribe( response => this._someStuff.next(response) );
}
QUESTION:
The above is what I found a good solution from my investigations to not leak the HTTP subscriptions out of the service, but there was also much discussion about the fact that you should unsubscribe form HTTP observables, even though they complete themselves. So I assume this is true for services as well.
But I never saw that the HTTP requests in services were unsubscribed nor were the subjects completed.
Since I expect this is necessary, the following shows the backenService
how I would expect it should be:
// backend.service.ts
export class BackendService implements OnDestroy { // A. //
httpSubs = new Subscription(); // B1. //
private _someStuff = new BehaviorSubject<any>(null);
readonly someStuff = this._someStuff.asObservable();
constructor(http: HttpClient) { }
getStuff() {
this.httpSubs.add(this.http.get('...') // B2. //
.subscribe( response => this._someStuff.next(response) )
);
}
// rest of CRUD implementations
// ...
ngOnDestroy(): void {
this.httpSubs.unsubscribe(); // B3. //
this._someStuff.complete(); // C. //
}
I marked things (A.-C.) that are not as I have seen in common tutorials and stuff.
If I don't miss something fundamental about components,services and how missing unsubscriptions might cause side effects... then my questions regarding if unsubscirbe/complete in a service is necessary are:
I expect now that we have the subscription in the service, it is mandatory to implement OnDestroy here (A.), as we do in the components to be able to unsubscribe correctly. I guess this is even the case when the service is provided in root (and therfore will destroyed as one of the last parts of the application), since it might be possible that the service causes side effects on another root service that also isn't garbage collected yet.
Is this correct?If we don't unsubscribe in the servie, we will face the same problems as when we wouldn't unsubscribe in the component. Therefore B 1 - 3 are added (in fact the type how to unsubscribe is not important - only the fact we do - I choose the native RxJS approach)
Is this correct?
(side note: I'm aware that it might be a better approach not to unsubscribe and handle the side effects manually in some cases, but lets ignore this so the question don't gets to broad)
- I don't know how
.asObservable
works internally, but there have to be some subscriptions as well.
So is it necessary to complete the behaviour subjects (or normal subjects) like_someStuff
(C.)?