BAM

Use the $destroy event to solve memory leaks

TL;DR

  • Controllers in Angular can introduce memory leaks if not properly cleaned up.
  • When a controller is destroyed, it emits a $destroy event that can be used to clean up variables and DOM event listeners.
  • An example of how to use $destroy is provided in the article.

Introduction

Angular is a convenient but complex framework that makes it easy to connect your model to your view using controllers. However, as your app grows, the number of controllers in it increases, and it's easy to introduce leaks by not cleaning up after your controllers. In this article, we'll discuss how to avoid this problem by using the $destroy event.

The $destroy Event

When a controller is destroyed, it emits a $destroy event that you can listen to inside your controller. This is the point in your controller where you can delete data that might otherwise stay bound (bound data won't be reclaimed by the garbage collector), clean up DOM event listeners, etc.

Example of how to use $destroy

Luckily, when a controller is destroyed it will emit the ++code>$destroy++/code> event, which you can listen to inside your controller by using:

++pre>++code>myApp.controller('myController', function($scope) {

 ... // Your controller code goes here

 $scope.$on('$destroy', function() {
     // Do your clean up
});
++/code>++/pre>

This is the point in your controller where you can delete data that might otherwise stay binded (binded data won't be reclaimed by the garbage collector), clean up DOM event listeners, etc.

So, now that you know what ++code>$destroy++/code> is all about, let's try it out.

I set up a code pen where you can create or destroy a controller by clicking in the button ++code>Click to toggle controller++/code>. This creates a new controller that listens for a ++code>dispatched++/code> event and a button that emits said event. The listener logs when the controller was instantiated.

See the Pen <a href="http://codepen.io/tiagojdferreira/pen/JGmxbO/">JGmxbO</a> by Tiago Joel Domingues Ferreira (<a href="http://codepen.io/tiagojdferreira">@tiagojdferreira</a>) on <a href="http://codepen.io">CodePen</a>.

Since we are using ++code>$scope.$emit++/code> and ++code>$scope.$on++/code> the controller cleans up after itself. To verify this, do the following:

  • create a controller with the toggle button
  • dispatch an event
  • see the date in the console log
  • Destroy the controller with the toggle button
  • Repeat

This will give you two different dates for the two times the controller was instantiated.

Using $destroy with Non-Angular Events

Unfortunately, these functions only work for events dispatched in angular, so if you had an event emitted using ++code>element.dispatchEvent++/code> from another library (a chart, a react component; etc.) you couldn't use ++code>$scope.$on++/code> to listen to it.

A first approach would be to replace the ++code>$scope.$on++/code>, with a ++code>document.addEventListener++/code>. This, however, will create a new listener in the document element every time you create a new controller.

See the Pen <a href="http://codepen.io/tiagojdferreira/pen/YwJBPa/">YwJBPa</a> by Tiago Joel Domingues Ferreira (<a href="http://codepen.io/tiagojdferreira">@tiagojdferreira</a>) on <a href="http://codepen.io">CodePen</a>.

If you test the buttons now, you will see that we log once for every controller that was instantiated, so even though the controller was destroyed, the eventListener attached to the document element is still there.

To fix this, enter the ++code>$destroy++/code> event. All you have to do is listen to it using ++code>$scope.$on++/code> and use ++code>document.removeEventListener++/code> to remove the listener. Just add this to your controller:

++pre>++code>$scope.$on('$destroy', function() {
 console.log('clean up');
 // Remove the listener
 document.removeEventListener('dispatched', listener);
});
++/code>++/pre>

If you now try the buttons, it should all work as expected.

Conclusion

By using the $destroy event, you can avoid memory leaks in your Angular controllers. It's a simple but effective way to ensure that your app stays responsive and efficient.

Développeur mobile ?

Rejoins nos équipes