Visitors are also reading...
← PreviousNext →

Angular - 5 lines of code to prevent memory leaks

12 Oct 2015

5 lines of code in angular written once can affect your entire project by auto releasing resources and cancel delayed action after navigating away from the page. in this post i will explore and explain the problem and its solutions.

The problem

Programmers usually miss it, but if you use $timeout or $interval, or even $http - the promise lives beyond the scope. So if you navigate back and forth between pages, you get a leak of unreleased resources or some other unwanted behavior.

and then upsetting things can happen. imagine a simple redirect after an ajax request success:

$http.get( .. ) .then( function(){ $location.path(.. ) }

or polling every second?

$interval( func, 1000);

what most people don't know is that you have to cancel them with scope destruction..
Here is first result in google: Ben Nadel's - Don't Forget To Destroy Events You probably missed that, or missed something somewhere and there are leaking pollings and stuff in your code that you are unaware of. That's a shame because with probably 5 lines of code you can improve the behavior and performance of your code.

How to destroy events the ugly way?

simply(?) do $scope.$on('$destroy', .. ).
Some people will do $onLocationChange or something nasty, just so they won't have to work hard.. but that's uuuuuglly... don't you agree? just for a single scenario.. not a complete solution

How to destroy events the pretty way?

since I want events to exist only with scope, wouldn't that be most intuitive to have $scope.$interval for example? or even $scope.$http so that if the scope is destroyed, the event is cancelled. Well, here is how you do that

angular.module('mograblog', [])  
    .run(function($rootScope, $interval) {  
        // add the register task to the rootScope. This will allow for autoUnregister when the  
        // scope is destroyed to prevent tasks from leaking.  

        var ScopeProt = Object.getPrototypeOf($rootScope);  
        ScopeProt.$interval = function(func, time){  
             var timer = $interval(func,time);  
             this.on('$destroy', function(){ $timeout.cancel(timer); });  
             return timer;  
        };  
    });

this solution uses the fact that scopes has a prototypical inheritance and adds a function to all scopes (including isolated). This function will simply cancel the interval. Same thing can be done for the rest. and that's it!

← PreviousNext →