Search code examples
angularjsperformanceangularjs-scopewatch

Is there a more performant alternative to $watch in AngularJs?


We have a huge enterprise Angular application we are having performance issues, sometimes it kills the browser(out of memory). We debug the app using browser developer profiler (DevTools), and it takes lot of time on $apply() function.

I did some research and it looks like $apply() is fired every time angular runs the digest cycle.

I noticed a significant amount of $watch() in controllers. The architecture is entirely based on $watch() (it is a kind of subscribe/observe pattern). Because of that, we have no other option but $watch(). I am not allowed to publish any code of this application.

So, my question is, is there a more performant alternative to watch data structures, so the performance of the application can be improved?


Solution

  • Without an specific example of code will be hard to determine where your performance problem is. However the answer to your question is yes. as a matter of fact, I wrote an article about it, no long: optimizing-code-object-defineproperty-scope-watch-angularjs

    You can achieve the same functionality of a watch more efficiently with Object.defineProperty() (see code example below) Note: this solution is not supported by IE8 and below.

    var myApp = angular.module('myApp', []);
    myApp.controller('MyCtrl', MyCtrl);
    myApp.service('efficientWatch', efficientWatch);
    
    
    MyCtrl.$inject = ['efficientWatch'];
    
    function MyCtrl(efficientWatch) {
        var self = this;
        efficientWatch.watch('reactionText', self, function (newval) {
            if (newval == 'watched') {
                self.reacted = true;
            }else{
                self.reacted = false;
            };
        });
        self.reacted = false;
        self.placeholder = 'type the watched word';
    }
    
    function efficientWatch() {
        this.watch = function (name, controllerProto, func) {
            Object.defineProperty(controllerProto,
            name, {
                get: function () {
                    return this._personName;
                },
                set: function (newValue) {
                    this._personName = newValue;
    
                    //Call method on update
                    if (typeof func == 'function') func(newValue);
                },
                enumerable: true,
                configurable: true
            });
        };
    };
    

    Hope this was help you ;)