AngularJS dirty checking performance - angularjs

In the angular scope, I have a huge object scope.a, and somehow I have another scope.b reference to it.
I know angularJS uses dirty checking, so we should reduce the stuff inside scope. My question is, since a and b are essentially the same obj(reference). Will it have noticeable performance improvement if I manage to get rid of b, keep only one reference?

Just having something in the scope does not have any performance implications on the $digest cycle (See Integration with the browser event loop here: https://docs.angularjs.org/guide/scope).
The dirty checking ($digest cycle) calls any registered $watch functions (manually registered in your code or registered in the angular code), and then calls the listener function if the $watch function returned anything different from last time.
To answer your question, no there won't be any performance improvement by not adding something to the scope. Performance is most readily improved by improving performance of any $watch functions, since they are always called at least once every $digest cycle.

Related

Does $evalAsync makes $scope.$apply unnecessary?

From my understanding, $evalAsync will queue the changes to the current digest cycle if it can, if not then to the next one.
So in which cases would i use $scope.$apply ?
Both of them run digest on the $rootScope, but $evalAsync have the possibility to make it faster by hooking into the current digest cycle, which sounds better in 99% cases.
I have seen this info below link , I felt good may it will useful to you !
http://www.codingeek.com/angularjs/angular-js-apply-timeout-digest-evalasync/
$evalAsync() is a new function which was first introduced in AngularJS 1.2.X, and in my opinion it is the adroit version of $timeout().
Before $evalAsync() came into the picture, AngularJS team recommended using the $timeout() in case of digest cycle issue, described above.
As AngularJS evolved for large apps and digest cycle became common and then Angular team introduced $evalAsync(). This function will evaluate the expression during the current cycle or the next.
Suppose you call some expression on $evalAsync() and any digest cycle is going on at the same time. All expressions from $evalAsync() will be added to the queue and they will be part of the current lifecycle and no new digest cycle will be invoked. This is why $evalAsync() make it more efficient because it reduce the possibility to create new digest every time.
If there is not any digest is going on, it will work similar to $timeout. It will create a callback with default time (10 ms) and after this time (10 ms), there will be a new digest on rootScope and all expressions will be evaluated.

Too many listeners and slow $compile, need performance tips or something between two-way binding and one-time binding

Sorry, I don't have a live example, I'm looking for performance advice.
I've finally hit my first performance problem with angular, I have a pretty complex UI and in it, I have a directive with about 3 nested repeats that use directives, in every level the directive uses scope: true and using bindToController syntax.
The data source is not that big, but every repeat ends up being between 30-100 watchers (I'm using this snippet to count the watchers)
I'm calling $compile on the top directive and it takes way over a second (!) to show the HTML (it ends up having a few hundred listeners), ng-if and ng-class and other custom directives, it quickly adds up.
I've added one-time bindings wherever I could, but I'm still at way over a 1000 in total and I guess that can slow things down?
I've ran CPU profilers in different browsers, drilled as deep as possible and I never saw my code taking up and significant time, all I see it jquery/angular taking a long long time, but none of the functions inside show any significant self time.
If I open that 800ms elemData.handle, all I see is angular's $scope.eval, compileDirectives and a bunch of other angular stuff in a deep tree.
Could using scope: true be the culprit? Would complex directives perform better if they use an isolate scopes?
Maybe there are advanced methods I don't know to use one-time bindings? Or something between two-way and one-way?
EDIT: for posterity, this is what happened: I managed to replace my isolate scope directives on the inner-most ng-repeat level with simple ng-includes, the functionality is the same, but execution time is 1/1000. I don't think I'll ever really know why the difference was so huge, I never had many items in the ng-repeat, but the code now runs in 1ms :)
Use $destroy events to clean up event watchers
Use one-way-binding everywhere what you can't change manually (ng-repeat, ng-options)
In templates try to avoid functions that will return value. Simple assignment not needed to be compiled but function will run each $digest (ng-if="ctrl.isDataLiading()" slower then ng-if="ctrl.isDataLoaded")
In list items with a lot of ng-repeat avoid filters that will recount and run collection watchers on arrays that is taking great portion of performance - instead use ng-if to remove filtered items
When I was implementing tree structure that can be like expanded to see child nodes (list with + option) I struggled with such problem. Above approach made functionality better but speed did not rise a lot.
In common words all my answer means: angular populates too many watchers, get rid of them

$scope.$evalAsync vs $scope.$applyAsync

What is the difference between $evalAsync and $applyAsync? My understanding is that when I use $evalAsync from a directive, the expression will evaluate before the browser renders.
So as an example, if I wanted to scroll to a particular position on a page but not show the jump to that spot, I could use this to scroll to the position and since it fires before the browser has rendered, this visual bug would be gone.
However, what is the purpose of applyAsync? When is it a good idea to use one over the other?
The
$evalAsync()
will execute in the current digest
$applyAsync()
in a scheduled one.
If you need details:
Ben Nadel or stack here
Here is what I have been using $applyAsync for. Basically, I use this as a safe $apply. You know that annoying error when you try to trigger a digest when one is already in progress? If you use $applyAsync, you will get another digest, but it will occur when the current digest cycle has completed.
$applyAsync is also cool since you can batch up a bunch of callbacks to fire within then next digest.

Is it an antipattern to use angular's $watch in a controller?

In my never ending quest to do things the "proper" angular way, I have been reading a lot about how to have controllers observe the changes in models held in angular services.
Some sites say using a $watch on a controller is categorically wrong:
DON'T use $watch in a controller. It's hard to test and completely unnecessary in almost every case. Use a method on the scope to update the value(s) the watch was changing instead.
Others seem fine with it as long as you clean up after yourself:
The $watch function itself returns a function which will unbind the $watch when called. So, when the $watch is no longer needed, we simply call the function returned by $watch.
There are SO questions and other reputable sites that seem to say right out that using a $watch in a controller is a great way to notice changes in an angular-service-maintained model.
The https://github.com/angular/angular.js/wiki/Best-Practices site, which I think we can give a bit more weight to, says outright that $scope.$watch should replace the need for events. However, for complex SPA's that are handling upwards of 100 models and REST endpoints, choosing to use $watch to avoid events with $broadcast/$emit could end up with lots of watches. On the other hand, if we don't use $watch, for non-trivial apps we end up tons of event spaghetti.
Is this a lose/lose situation? Is it a false choice between events and watches? I know you can use the 2-way binding for many situations, but sometimes you just need a way to listen for changes.
EDIT
Ilan Frumer's comment made me rethink what I'm asking, so perhaps instead of just asking whether it is subjectively good/bad to use a $watch in a controller, let me put the questions this way:
Which implementation is likely to create a performance bottleneck first? Having controllers listen for events (which had to have been broadcast/emitted), or setting up $watch-es in controllers. Remember, large-scale app.
Which implementation creates a maintenance headache first: $watch-es or events? Arguably there is a coupling (tight/loose) either way... event watchers need to know what to listen for, and $watch-es on external values (like MyDataService.getAccountNumber()) both need to know about things happening outside their $scope.
** EDIT over a year later **
Angular has changed / improved a lot since I asked this question, but I still get +1's on it, so I thought I would mention that in looking at the angular team's code, I see a pattern when it comes to watchers in controllers (or directives where there is a scope that gets destroyed):
$scope.$on('$destroy', $scope.$watch('scopeVariable', functionIWantToCall));
What this does it take what the $watch function returns - a function that can be called to deregister the watcher - and give that to the event handler for when the controller is destroyed. This automatically cleans up the watcher.
Whether watches in controllers are code smell or not, if you use them, I believe the angular team's use of this pattern should serve as a strong recommendation for how to use them.
Thanks!
I use both, because honestly, I view them as different tools for different problems.
I'll give an example from an application that I built. I had a complex WebSocket Service that received dynamic data models from a web-socket server. The service itself doesn't care what the model looks like, but, of course, the controller sure does.
When the controller is initiated, it set up a $watch on the service data object so that it knew when it's particular data object had arrived (like waiting for Service.data.foo to exist. As soon as that model came into existence, it was able to bind to it and crate a two-way data-bind to it, the watch became obsolete, and it was destroyed.
On the other side, the service was responsible for broadcasting certain events as well, because sometimes the client would receive literal commands from the server. For instance, the Server might request that the client send some metadata that was stored in the '$rootScope' throughout the application. an .on() was set up in the $rootScope during module.run() step to listen for those commands from the server, gather needed information from other services, and call the WebSocket service back to send the data as requested. Alternatively, if I had done this using a $watch(), I would have needed to set up some sort of arbitrary variable for it to watch, like metadataRequests which I would need to increment every time I receive a request. A broadcast achieves the same thing without having to live in permanent memory, like our variable would.
Essentially, I use a $watch() when there is a specific value that I want to see change (especially if I need to know the before-and-after values), and I use events if there are more high-level conditions that have been met that the controllers need to know about.
With regards to performance, I couldn't tell you which one is going to bottleneck first, but I feel like thinking of it this way will let you use the strengths of each feature where they are strongest. For instance, if you use $on() instead of $watch() to look for changes in data, you will not have access to the values before and after the change, which could limit what you are trying to do.
All that two-way data-binding is, is a $watch on whatever scope property you give to ng-model, which has a controller that allows other directives like input, and form to sync the ng-model value to render the view on a change. Which is detected by their registration of events in the DOM.
In essence,ng-model's $watch compares the value in the model, to the value it has internally. The value it has internally is set by supporting directives (input,form etc).
IMHO The only "events" you should react to in an angular application are user created (ie DOM events). These are solved with directives on the DOM and ng-model linking to the ..model
Also naturally there is async, for which angular provides $q for which the callbacks invoke a $digest.
As for performance, it says it really well in the angular docs. Its run on every $digest. So make it fast. Whats every $digest? Angular traverses all of your active scopes. Each scope has watches. which it executes. and performs comparisons in those. If there are diffs, it will run again. (the next loop around) Its not that simple because its optimized but all of your "angular code" executes in this $digest loop. A lot of directives might invoke a digest with scope.$apply(...) That will cause watches of whatever value they changed to notice and do their thing.
So your original question. Is it an anti-pattern? Absolutely not if you know how to use it. Though I'd just use ng-model. Just because it has had 1.2.10+ iterations of pretty smart people working on it... All of the other 'reactive-ness' of your app can be handled by $q, $timeout and the like.
I think they all have their proper place and, for me, it would be difficult to say stop using one for the others.
Data binding should always be used to keep your data model in sync with changes from the view. I think we can all agree on that.
I think using a watch on a controller to trigger some action based on a data change is useful. Like watching a complex data model to calculate a running total for an invoice. Or watching a model to trigger it as dirty.
I have used broadcast/emit/on when sending a message or an indication of some change from one scope to another that may be several layers away. I have created a custom directive where a broadcast event has been used as a hook to take some action in a controller.

does angularjs $watch every property on a $scope or only those referenced in template?

Since all watches are evaluated on every $digest, keeping their number low is a good perf practice. To rephrase the question title, is there a perf penalty for declaring either a variable or method on $scope inside a controller, when those aren't being referenced by related template (if there is a penalty one could declare those as local variable on controller object instead).
When you place something on $scope, it can be watched. You can $watch anything on the scope perfecly fine, even if it is not on a template.
Is there a performance penalty? AngularJS usually compares references when you watch objects, and only compares the watched objects, not everything on the scope. So unless you are doing a deep compare on a very large object or array that you are watching, it should't take noticeable time.
For testing performance and seeing if your changes are slowing anything down, you can use the AngularJS Batarang.

Resources