Angular comes with a powerful concept known as Observables. This article will help you avoid one of the most common usage mistakes in your code: memory leaks.
At Sipios, we want to create websites that are appreciated by users, with the aim that they will recommend them to their friends and family. This is achieved through the responsiveness of the pages, their dynamism, and their response time. To do this, we use asynchronism. In JS, Promises manage asynchronous functions. Let's start by seeing the difference with observables!
Once the promise is fulfilled or rejected, it ends. It thus allows us to obtain a unique asynchronous response.
In the example below, the interval function is an observable that will transmit every 200 milliseconds to simulate a change in the flow:
The main advantage of observables is that they don’t destroy themselves after the first update of the variable. This characteristic can lead to a huge risk if we forget to stop listening: it will create a memory leak.
To illustrate this, we will create a simple website with one button “Trigger”. When we click on it, a list of 10 000 random numbers will be created every second. On our page, we will see the sum of each list. After a second click on our button, the component will be destroyed and lists too.
Here is the memory leak: when we click on the button for the first time, we create a child component that manages the lists. To do that, an observable will be triggered every second, and with that, the creation of a list. After the second click on the button, the child component will be destroyed, but not the observable because we didn’t clearly say that we would like to unsubscribe from it. That’s why, when we make the child component appear again, a new observable is created in addition to the old one. That’s why, the more we trigger the button, the more we see multiple values appear concurrently on our screen.
The first clue for a memory leak is…. the response time. The more actions we make on our website, the more time it takes to navigate between pages. In that case, you may just have found a leak. If the memory leak is caused by callbacks, you can verify this by seeing if you have duplicated calls in the Network view of your browser. Two other views that can help you detect leaks in other cases are:
Using unsubscribe is the basic method, the most known. The principle is quite simple: we store our subscribes in objects of type Subscription. And we destroy them when we want to stop listening to them. Most commonly, the destruction is done in the ngOnDestroy method (which is the last step of an Angular component lifecycle).
It is possible to use the add method of the Subscription class to chain several subscriptions. Doing so, if we destroy the first observable of the chain, all those that follow will be destroyed. This avoids writing the unsubscribe line several times. Of course, this method destroys all observables at once, so it is not to be used in all situations.
Another method to manage subscriptions in a controlled way is the use of RxJs functions in the pipe() of the observable. There are several of them that allow managing each observable in a unitary way: first(), take(), takeUntil() and takeWhile(). Let's try to understand their respective behaviors:
Without a doubt, it is the cleanest and most efficient (ahead of takeUntil) because it limits the amount of code written. It limits the forgetting because it associates the life cycle of the observable to the one of the HTML. You don't need to subscribe in the ".ts" and you call the observable at the place where you want to use it by adding "| async".
Even if this method is the cleanest, it has its limits! As explained,
, you should use one of the options above. This will avoid duplicating the code.
Observables are powerful tools for a dynamic website. But using them in an uncontrolled way could greatly decrease the performance of your website. You can anticipate memory leak problems by using different functions:
On the Bpifrance website, learning about memory leaks has allowed us to solve a lot of bugs and save up to 40% of loading time on certain pages.