Skip to content

Commit 22a4bc3

Browse files
committed
Update text
1 parent fa20977 commit 22a4bc3

File tree

1 file changed

+41
-27
lines changed

1 file changed

+41
-27
lines changed

README.md

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
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
33
from 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
66
that 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,
1933
since 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
5061
We 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.
6174
However, it can happen that the component cannot be garbage collected due to references used in observable callbacks.
6275

6376
We 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
```
7184
this.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.
8397
So the observable still runs after the ``RxjsTimerComponent`` was destroyed.
8498
So 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
89103
and ``this.titleService`` in the observables callback method.
90104

91105
In 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
98112
One countermeasure (among others at the end of this readme) is to manually unsubscribe in ``ngOnDestroy``.

0 commit comments

Comments
 (0)