AngularJS - Best practice: model properties when viewing or calling functions?

At some point I wondered about this question: when working with AngularJS, should I use the properties of the model object directly in the view, or can I use the function to get this property value?

I do small home projects in Angular and (especially working with directives or read-only controllers). I try to create region functions for accessing and displaying region objects and their property values ​​in views, but in terms of performance, is this a good way to go?

This method seems more convenient for maintaining the presentation code, because if for some reason the object is changed (due to server implementation or any other specific reason), I need to change only the JS directive code, not the HTML. Here is an example:

//this goes inside directive link function scope.getPropertyX = function() { return scope.object.subobject.propX; } 

in view i could just do

 <span>{{ getPropertyX() }}</span> 

instead

 <span>{{ object.subobject.propX }}</span> 

which is harder to maintain, among the HTML clutter that sometimes occurs. Another case is the use of scope functions to check property values ​​for evaluations on ng-if, instead of using this test expression directly:

 scope.testCondition = function() { return scope.obj.subobj.propX === 1 && scope.obj.subobj.propY === 2 && ...; } 

So, are there any pros and cons to this approach? Could you give me some idea about this problem? This has bothered me lately about how a heavy application can behave when, for example, a directive can become really complex, and besides, it can be used inside ng-repeat, which can generate hundreds or thousands of instances.

thanks

+7
javascript angularjs model-view-controller angularjs-directive
source share
3 answers

I don't think creating functions for all of your properties is a good idea. Not only will more function calls be made that will be executed every digest cycle to see if the value of the returned function has changed, but it really seems less readable and supported for me. It can add a lot of unnecessary code to your controllers and how to turn your controller into a viewing model. Your second case seems perfect, complex operations are similar to what you want your controller to handle.

As for performance, this makes a difference in accordance with the test I wrote (the script tried to use jsperf, but could not get different settings for each test). The results are almost twice as fast, i.e. 223,000 digests / sec using properties compared to 120,000 digests / sec using getter functions. The watch is designed for bindings that use angular $parse .

One thing to think about is inheritance. If you uncomment the ng-repeat list in the fiddle and inspect the scope of one of the elements, you can see what I'm talking about. Each created child region inherits the properties of the parent region. For objects, it inherits the link, so if you have 50 properties on your object, it only copies the reference value of the object to the area of ​​the child object. If you have 50 manually created functions, they will copy each of these functions to each child region to which it inherits. Timings are slower for both methods, 126,000 digests / sec for properties and 80,000 digests / sec with getter functions.

I really don't understand how it would be easier to maintain your code, and it seems to me that this is more difficult. If you don't want to touch your HTML if the server object changes, it would probably be better to do this in a javascript object instead of putting getter functions directly in your scope, i.e.:

 $scope.obj = new MyObject(obj); // MyObject class 

In addition, angular 2.0 will use Object.observe (), which should improve performance even more, but will not improve performance using getter functions in your area.

It looks like this code is executed for every function call. It calls contextGetter() , fnGetter() and ensureSafeFn() , as well as ensureSafeObject() for each argument for the scope itself and the return value.

 return function $parseFunctionCall(scope, locals) { var context = contextGetter ? contextGetter(scope, locals) : scope; var fn = fnGetter(scope, locals, context) || noop; if (args) { var i = argsFn.length; while (i--) { args[i] = ensureSafeObject(argsFn[i](scope, locals), expressionText); } } ensureSafeObject(context, expressionText); ensureSafeFunction(fn, expressionText); // IE stupidity! (IE doesn't have apply for some native functions) var v = fn.apply ? fn.apply(context, args) : fn(args[0], args[1], args[2], args[3], args[4]); return ensureSafeObject(v, expressionText); }; 

},

In contrast, simple properties are compiled something like this:

 (function(s,l /**/) { if(s == null) return undefined; s=((l&&l.hasOwnProperty("obj"))?l:s).obj; if(s == null) return undefined; s=s.subobj; if(s == null) return undefined; s=sA; return s; }) 
+8
source share

Everything you put in {{}} will be evaluated as a LOT. He must evaluate each digest cycle to see if the value has changed or not. Thus, one of the very important rules for angular is that you do not have expensive operations in any $watch es, including those registered through {{}} .

Now the difference between referring to a property directly or a function has nothing else but returning it seems negligible to me. (Please correct me if I am wrong)

So, while your functions are not performing expensive operations, I think this is really a matter of personal preference.

0
source share

Performance is unlikely

Jason Goemaat did an excellent job by providing benchmarking . Where you can change the last line:

 setTimeout(function() { benchmark(1); }, 500); 

to

 setTimeout(function() { benchmark(0); }, 500); 

to see the difference.

But it also forms the answer, because properties are twice as fast as function calls. In fact, on my mid-2014 MacBook Pro, properties are three times faster .

But equally, the difference between calling a function or accessing a property is directly equal to 0.00001 seconds - or 10 microseconds .

This means that if you have 100 getters, they will be 1 ms slower compared to accessing 100 properties.

Just to put things in context, the time required for sensory input (a photon hitting the retina) to reach our consciousness is 300 ms (yes, conscious reality is delayed by 300 ms). So you will need 30,000 getters on one screen to get the same delay.

Code quality is wise - it can make a big difference

In assembler assembly days, the software looked like this:

A collection of executable lines of code.

But at present, especially for software that has at least the slightest level of complexity, the view is as follows:

Social interaction between communication objects.

The latter concerns much more about how behavior is established through communication objects than real low-level implementation. In turn, communication is provided by an interface, which is usually achieved using the principle of a request or command . The important thing is that this is an interface (or contract between) collaborating objects, and not a low-level implementation.

By checking the properties directly, you find yourself in the internal objects of the object, bypassing its interface, thereby connecting the caller to the called user.

Obviously, with the help of getters, you can correctly ask what the point is. Well, consider these implantation changes that will not affect the interface:

  • Checking for extreme cases, for example, regardless of whether a property is defined.
  • Change the name getName (), which returns the first + last name, and not just the name property.
  • The decision to save the property in a mutable design.

Thus, even a seemingly simple implementation can change in such a way that if using getters requires only one change, where without it many changes will be required.

I run getters

Therefore, I argue that if you do not have a profiled case for optimization, you should use getters.

0
source share

All Articles