11# When should I unsubscribe from RxJS observables in Angular?
2- There's a lot of confusion in the community about the question if you have to unsubscribe
2+ There's a lot of confusion in the community about the question if and when you have to unsubscribe
33from RxJS observables in Angular.
44
5- Although there are some quite nice StackOverflow posts about this questions , there is no clear guidance
5+ Although there are some quite nice StackOverflow posts about this question , there is no clear guide
66that contains all relevant information explained by examples.
77
8- This repository provides the necessary Angular project to examine the problems by yourself and a guide for common situations.
8+ This repository provides a guide for common situations and an Angular project to examine the problems by yourself.
9+
10+ ## Angular components and observables
11+ The guide focuses on issues with components using observables.
12+
13+ A typical component lifecycle in an Angular CRUD application contains the following steps (in a simplified version):
14+ 1 . User navigates to component `` A ``
15+ 2 . Component `` A `` gets initialized (constructor and `` ngOnInit `` are invoked)
16+ 3 . Some logic is called to load data (e.g. using `` HttpClient `` ).
17+ _ Subscriptions to observables are made._
18+ 4 . User navigates to another component `` B ``
19+ 5 . Component `` A `` gets destroyed (`` ngOnDestroy `` is invoked)
20+ 6 . ...
21+
922
1023## Conclusion
11- Whether you have to unsubscribe or not heavily depends on the callback logic you are using.
24+ Whether you have to unsubscribe or not heavily depends on the callback logic you are using in the observables subscription .
1225
13- If the callback executes code with side effects you should always unsubscribe.
26+ If the callback executes code with side effects (affecting global application state) you should always unsubscribe
27+ when the component gets destroyed.
1428
15- If the callback uses member variables from the component class there can be a memory leak when using observables that don't complete,
16- therefore you should unsubscribe in that case.
29+ If the callback uses member variables from the component class, there can be a memory leak when using observables
30+ that don't complete, therefore you should always unsubscribe in that case.
1731
18- Observables that don't complete should be cancelled (almost) always,
32+ Observables that don't complete should be cancelled always,
1933since the callback logic still runs (infinitely) in the background otherwise.
2034
2135| | Side effects | Memory leaks | Should unsubscribe |
@@ -26,12 +40,9 @@ since the callback logic still runs (infinitely) in the background otherwise.
2640| _ Angular ActivatedRoute_ | No | No | No (4) |
2741| _ Angular Router events_ | Possible (1) | Possible (2) | Yes |
2842
29- (1): If you execute methods with side effects in the callback.
30-
31- (2): If you use member variables from the component in the callback.
32-
33- (3): Assuming the observable completes.
34-
43+ (1): If you execute methods with side effects in the callback.
44+ (2): If you use member variables from the component in the callback.
45+ (3): Assuming the observable completes.
3546(4): You don't have to, but are free to unsubscribe anyway.
3647
3748# Further explanation and examples
@@ -48,38 +59,41 @@ folder.
4859
4960## The questions and the study method
5061We want to answer the following questions in each case study:
62+
5163### 1. Can we run into the problem of unwanted side effects?
52- To investigate this issue, we use the realistic scenario, that we want to set the document title
53- dynamically on behalf of a observable. To this end, we use the Angular title service (https://angular.io/guide/set-document-title ).
64+ To investigate this issue, we use the scenario, that we want to set the document title (inside the component we navigated to)
65+ dynamically on behalf of a observable.
66+ To this end, we use the Angular title service (https://angular.io/guide/set-document-title ).
5467
55- We set the title in the observables callback, navigate to the `` EmptyComponent ``
68+ In each experiment, we set the title in the observables callback inside component `` XY `` , navigate to the `` EmptyComponent ``
5669(which does nothing else than setting its own title), and observe if the title still gets updated.
5770
5871### 2. Can we run into the problem of memory leaks?
59- We again route from our component of case study to the `` EmptyComponent `` . Under normal circumstances,
60- the component we came from should be garbage collected.
72+ We navigate from the component `` XY `` with the observable (we want to study) to the `` EmptyComponent `` .
73+ Under normal circumstances, the component `` XY `` should be garbage collected.
6174However, it can happen that the component cannot be garbage collected due to references used in observable callbacks.
6275
6376We will use Google Chrome's memory snapshot tool to see if the components get garbage collected or not.
6477
6578
6679## Observables that don't complete
67- The first and most trivial case is that you have an observable, that does not complete.
80+ The first and most trivial case is an observable that does not complete.
6881
69- Say you have a timer observable, like in our case study component `` RxjsTimerComponent ``
82+ Say you have a timer observable in your component , like in our case study component `` RxjsTimerComponent ``
7083```
7184this.subscription = timer(0, 1000)
7285 .subscribe(() => {
7386 this.counter++;
7487 this.titleService.setTitle('Counter ' + this.counter);
7588 });
7689```
77- The is an infinite timer observable, that emits each second. On each emit, we increase a counter and set
78- the document title with the title service.
90+ This is an infinite timer observable, that executes the callback each second.
91+ On each emit, we increase a counter and set the document title with the title service.
7992
8093### Outcomes
8194#### Side effects
82- As expected, after routing to the `` EmptyComponent `` , the document title gets updated each second.
95+ As expected, after routing from the `` RxjsTimerComponent `` to the `` EmptyComponent `` ,
96+ the document title gets updated each second.
8397So the observable still runs after the `` RxjsTimerComponent `` was destroyed.
8498So we have an unwanted side effect in our example.
8599
@@ -89,10 +103,10 @@ get garbage collected. This makes sense, since there is still a reference to ``t
89103and `` this.titleService `` in the observables callback method.
90104
91105In fact, by navigating back and forth between `` EmptyComponent `` and `` RxjsTimerComponent `` we can create many
92- `` RxjsTimerComponent `` objects that doesn 't get cleaned up. Thus we indeed created a memory leak issue in our example.
106+ `` RxjsTimerComponent `` objects that don 't get cleaned up. Thus we indeed created a memory leak in our example.
93107
94- NOTE: If you don't use any references (like member variables) from the component in the callback, the component gets garbage collected
95- and there is no memory leak.
108+ NOTE: If you don't use any references (like member variables) from the component in the callback,
109+ the component gets garbage collected and there is no memory leak.
96110
97111### Countermeasures
98112One countermeasure (among others at the end of this readme) is to manually unsubscribe in `` ngOnDestroy `` .
0 commit comments