When reading about one-way binding in angular.component style, I came across multiple statements that < vs = produces less watchers (= will have additional watcher to propagate value change from child to parent).
However I've just created a dummy component, passed the object to it via = and < and number of watchers is the same.
So speaking strictly about performance: are there any diffirence between < and = ?
I came here with the same question, and was disappointed to see no answer...
I have a small test application where I use all kinds of binding, three of them being one-way. I observed the number of watches (using ng-stats utility), got 42.
I changed these "<" to "=", which changed the behavior of my app accordingly, of course. ng-stats still reported 42 watches.
So, at least in terms of watches, this brings no performance improvement.
I guess it is here more as a convenience, avoiding unwanted side effects (child changing a value, parent's value being changed unwillingly) and promoting good practices (using bound functions instead of watches, as explained below).
It can still be a way to avoid watches: a common practice when a parent wants to be advised of changes in a child it is to use two-way binding, set up a watch on the value, and react on changes.
An alternative is to set up a one-way binding (to feed the child), and to provide a callback (via a "&" binding), and thus to let the child to notify of changes via this callback.
It is more proactive and it removes a watch.
Related
Is it possible to create a watcher that is tied to an object such that
1) the watcher's handler function uses the object but does not prevent it from garbage collected; and
2) if the object is garbage collected, the watcher is also de-registered
The use case is that a component has a collection of internal "helpers" that caches derived data, so they need to $watch scope variables of the parent. However, they are not angular components (no individual scopes for them) and they're added/removed dynamically without a way of hooking their life-cycle.
I guess I can $watch the collection and process the any removals manually, but this seems extremely cumbersome. A more direct solution is welcomed.
I'm currently working on the performance of an angularJS application, and was wondering if there is any difference in performance between these two examples:
http://plnkr.co/edit/T5aHybkkCoF5MDzXX2Kk?p=preview
http://plnkr.co/edit/sX2ffPPOQTyFbb70elwp?p=preview
The difference is that in the first example, in the file 'testdirective.html' the ng-if boolean is not bound in a one time expression. However, it is already bound as a one-time binding in the 'index.html'.
<div ng-if="enabled">
vs
<div ng-if="::enabled">
Is using a one-time expression in the directive as well as in the index file better for the performance?
Thanks!
Yes, there will be a performance difference (although negligible in this case).
The directive doesn't take into account if the value passed to it was one-time bound or not, so if the directive's template doesn't use a one-time binding it will register a new watcher.
The cost of running this watcher during the digest cycle will bascially be the difference in performance in the two examples.
An extra note on your example that doesn't really touch the question is that the following two cases will behave the same:
<testdirective enabled="::true"></testdirective>
And
<testdirective enabled="true"></testdirective>
In the second case true will be treated as a constant that cannot change and the registered watcher will be removed, just like with a one-time binding.
I have extended my entities, which are provided by breezejs, with properties that are the result of a recursive call to the property. The property is display only and I never want to store the value.
In particular I added a "start" and an "end" property which depends on the "end" date of the entity before it and the timespan of the current entity. These values are deterministic and there is no sense in storing them. This works brilliantly until I have a few thousand entities. At this point performance tanks due to the two way binding as a result of all of the properties that were touched during the calculation.
I have a caching scheme in place and simply want angularjs to do nothing during the calculation of the "start" and "end" properties.
How can I prevent any watchers/two way binding from occurring while I am calculating these properties?
In a broader sense, how can you work with large amounts of data within angularjs without drowning in watchers?
Edit:
Something like this appears to be the solution:
https://coderwall.com/p/d_aisq/speeding-up-angularjs-s-digest-loop
Where the watchers in the scope are suspended during an operation and then resumed after I am done.
var watches = scope.$$watchers;
scope.$$watchers = [];
// do fast computation that touches a lot of data
scope.$$watchers = watchers;
Edit 2:
This is before binding to the view, this is in assembly data for binding. I don't think one time bindings can be done in the controller?
Like #zeroflagL's suggestion, one time binding is an option that's available
An expression that starts with :: is considered a one-time expression. One-time expressions will stop recalculating once they are stable, which happens after the first digest if the expression result is a non-undefined value
Expressions # angularjs.org
Also, if you want to start a calculation that won't trigger a digest cycle, don't change any members on the $scope. Just use "var" and in the end of the process do $scope.data = newValue;
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.
From my understanding the attributes of a Backbone.js model are supposed to be declared as somewhat private member variables by saying
this.set({ attributeName: attributeValue })
// accessing the value
this.get('attributeName');
But when I am writing functions whitin the actual model it seems much simpler to say like this:
this.attributeName = attributeValue;
// accessing the value
this.attributeName;
Also I would assume that the latter version would be faster to process since it doesn't go through backbone.js's event management.
So I was wondering how you pros do with attributes that are primarily used internally in the model. These are the attributes that one would actually want to be a bit shielded from the outside so having them exposed like in the latter example maybe isn't right still. When I have been looking at examples for the backbone.js view which doesn't have get and set methods it seems fine to do like in the second example. So is there any nice rule of thumb when to use get/set(attribute) or this.attribute when coding within the model? Or maybe an example of a model that makes this clearer?
When to use model.get(property) and model.set(...)
You should use get and set to access the model's data. This means any attributes that are part of the model's serialized representation that is retrieved using fetch and persisted using save.
When to use model.attributes.property
Never.
You should always use get, and especially set, instead of accessing the model.attributes object directly, although I've seen conflicting opinions about this. I believe there is a contract between a model and it's consumers, which guarantees that the consumer can be notified of any changes to the model's data using the change event. If you modify the internal attributes object directly, events are not sent and this contract is broken. Backbone events are very fast, especially if you don't have any listeners attached to them, and it's not a point that benefits from over-optimization on your part.
Although accessing the attributes directly instead of get is quite harmless on it's own, it should be avoided so the attributes object can be considered totally, completely private.
If you absolutely need to prevent some change triggering events, you can use the silent:true option: model.set({key:val}, {silent:true}). This does break the aforementioned contract, and even Backbone's own documentation gives the following caveat:
Note that this is rarely, perhaps even never, a good idea. Passing through a specific flag in the options for your event callback to look at, and choose to ignore, will usually work out better.
When to use model.property
Any properties which are not data, i.e. temporary state variables, calculated properties etc. can be attached directly to the model entity. These properties should be considered temporary and transitive: they can be recreated upon model initialization or during its lifetime, but they should not be persisted, whether public or private. A typical naming convention is to prefix private properties with the _ character as follows:
this._privateProperty = 'foo';
this.publicProperty = 'bar';
Never is an incomplete answer.
Sometimes you want access to the collection of model attributes - whatever those attributes might be. Consider a utility method to perform calcs on attributes, format them for output, etc.
A convenient way to do this is to access model.attributes
Consider one alternative, below:
var attributesNames = ['foo', 'bar', 'baz'];
var attributes = _(attributesNames ).map(function(attr) { return model.get(attr); });
callSomeUtilityMethod(attributes);
Two problems:
We've introduced coupling in the "attributeNames" collection. What if that list changes?
We've lost the association of name/value. We could rewrite the map above, but it becomes more work.
In this scenario, it's much more convenient to do something like this:
callSomeUtilityMethod(model.attributes);