I want to create a bunch of generic components (angular 1.5) with multiple optional bindings that would be used inside multiple applications.
I am afraid it will create a lot of unnecessary watchers for an application that doesn't use most of the optional bindings.
Example:
Component declaration:
let dateRangeComponent = {
bindings: {
label: '@',
name1: '@',
name2: '@',
model1: '>?',
model2: '>?',
extra1: '>?'
},
template: `<div ng-if="$ctrl.model1>stuff</div>
<div ng-if="$ctrl.model2>stuff</div>
<div ng-if="$ctrl.extra1>stuff</div>`
};
Component use example:
<date-rage-component label="Pretty Date" name1="Start" name2="end"/>
My question is if it is possible to automatically unwatch all the stuff related to the unused optional bindings, knowing they are undefined at compile time.
For instance, imagine I want to use a component in my application where it doesn't need any of the optional Binding, angular would create a lot of unnecessary watchers to keep the ng-if updated when we know they will always be false.
Am I doing an early performance optimization when not needed or misunderstanding any concept?
I thought of creating a custom wrapper directive to take advantage of the lazy transclude compilation in angular 1.5
Something like this (pseudo-code, not tested):
<optional-binding-once ng-if="::attrs.model1">
<div ng-if="attrs.model1">
stuff
</div>
</optional-binding-once>
In this way I think the code inside optional-binding-once would only be compiled if ng-if is true, thus reducing one watcher if a binding is not defined.
(EDIT) Some Conclusions after some tests and research
Well, I guess there isn't a trivial solution to reduce the number of watchers inside a component when optional bindings are not filled.
I ran some tests through the $digest phase of angular, to check if the increased number of this kind of watchers is really a problem.
Here are my results:
The tests were against a worst-case scenario having 888 components with 4 optional bindings.
Chrome - Without optional bindings ( 888 component, total watchers 889)
- Total Watchers: 889
- Last Digest Cycle time: 0.9950000000026193
- Average time for the last 1004 digest cycles: 1.0544920318724353 ms
- starting dom loading (400ms)
Chrome - With optional bindings ( 888 component, 4 optional bindings, total watchers 4441)
- Total Watchers:4441
- Last Digest Cycle time: 1.1549999999988358
- Average time for the last 1001 digest cycles: 1.6851748251747816 ms
- starting dom loading (600ms)
Safari - Without optional bindings ( 888 component, total watchers 889)
- Total Watchers: 889
- Last Digest Cycle time: 1.0849999999991269
- Average time for the last 530 digest cycles: 1.211632075471664 ms
Safari - With optional bindings ( 888 component, 4 optional bindings, total watchers 4441)
- Total Watchers: 4441
- Last Digest Cycle time: 1.7450000000026193
- Average time for the last 588 digest cycles: 2.1167176870748237 ms
Conclusions:
In a worst-case scenario, the $digest time will be increased by 1ms. I don't think this rise will be a bottleneck for my application performance. This kind of watchers will fail in the first $digest condition ( value = get(current)) !== (last = watch.last) && etc ...), thus having a small impact in the processing time, because they never change or get the angular context dirty!