pitfalls of IIFEs with AngularJS - angularjs

I have an application made with angularJS, whole application is composed of IIFEs(Immediately Invoked Function Expression). Every module, directive, controller is itself an IIFE and they are around 100s.
I want to know what is the performance pitfall when an app has so many IIFEs.
It is OK to use IIFEs with AngularJS?
How good is using libs like browserify and requirejs with AngularJS for managing the dependencies?
Can you please throw some light on this?

The question you need to ask first is whether you've got some internal parts within the IIFE that you don't want to expose to the global scope.
The whole point of creating a closure in this manner is to mimic encapsulation and avoid polluting the global scope.
The performance pitfall is not so easy to measure; I think the performance issue is negligible when you create the IIFE (don't forget you're just creating a function). One performance issue that I might think of is that when you reference a function variable form an inner function, you need to travel through the scope chain and get it from the closure object.
I would recommend you to look at patterns like module pattern, revealing module pattern etc. I personally use the revealing module pattern.
Browserify and requireJS are two libraries that implement two different specs; the commonJS and AMD respectively. These two specifications try to accommodate a functionality that is not supported by ES3 or ES5; That is a way of defining module and then loading them in specified locations.
If you want to define modules and load them synchronously in a similar manner to hose nodeJS works, you can use Browserify. In addition, Browserify allows you to use the same modules both for client-side and server-side (as long as you're using nodeJS).
On the other hand if you want to asynchronously load your modules you can go with AMD and requireJS, but you won't be able to reuse them on the back-end.
Finally, bare in mind that everything you've mentioned is not directly connected to angularJS; those are some good JavaScript practises to overcome some issues of the language itself. It can be well used whether you're working with angular or not.
I would recommend that you use either browserify or requireJS; it will benefit you in the long run. Just imagine having 100 JS files; you would need to out the manually into your html in the correct order based on the dependency graph. You can easily come across issues like race conditions where one file should have been inserted before another one.
As for the performance overhead of IIFEs, you shouldn't have any serious issues.

As another answer said, IIFEs are a good general practice, independent of AngularJS.
If you're concerned about the performance of IIFEs, go ahead and check out these performance tests on JSPerf (or write your own):
http://jsperf.com/iife-antecedents-in-js
http://jsperf.com/immediate-anonymous-function-invocation
While some ways of IIFE creation are clearly much slower than others, I wouldn't worry about the performance of IIFEs unless you're in a large loop.

Related

Is there any such time when making a service accessible on the $root is acceptable?

Now, I know global variables is an anti-pattern, and perhaps more so in an Angular world than in other places... however, I have come across a use case where I'm leaning towards breaking the rule...
I have read the comments here, and strongly agree with all the posters who point out the anti-angular'ism my idea represents and the anti-pattern it generally is...
Angular JS - Make service globally accessible from controllers and view
However, now for my use case, I have a $theme service which contains a lot of variables and constants, such as paths to images and strings.
We also have a framework of components which are all made accessible to application designers via directives, allowing most of our applications to be build using just our internal framework in the form of markup directives.
I could make directives for each of the needs, however it would sacrifice the flexibility of having low coupling between views and themes, by allowing developers to access the $theme service directly in the views, without having to (re)write controllers (or even create controllers for everything) or implement new directives, it would allow them to work purely in the markup made available to them by the internal framework. Basically I want to enable application designers to be able to work purely in markup.
We also have made directives which wrap references to ngResource and exposes the methods of the resource on the current $scope as well as directives which binds the current $scope to variables on the $stateParam service, etc, etc, hopefully you get the picture...
e.g.
<h1>{{$root.$theme.NAME}}"</h1>
<img my-src="$root.$theme.logo.url" />
instead of lots of code with controllers and directives...
<my-theme-name />
<h1 my-theme-name />
<my-theme-logo />
<img my-theme-logo />
The difference between these two approaches is that the ones where the directive is attached a primary tag, it's purely a decorator, where in the former cases where the directive is the primary tag, the directive template will determine the resulting primary tag. A slight difference yielding a larger degree of flexibility in the approach where we are using the directives purely as decorators and not information experts.
However, instead of having to write directives all together, perhaps for things which are purely added to the individual theme, just to be used in a single app, in which case adding support in the $theme service seems to be wrong approach...
However, going with a strict custom directive driven approach, it will possibly allow us to more easily port to e.g. Angular2 or even something else by simply building an adapter or transpiler, without having to rewrite any of the markup, but simple rewire the directives to new controllers and handlers written in the new library.
So, back to my question, provided we work around this caveat for the testing, would it be a viable approach, or is it a slippery road to global variable hell where soon we will have polluted our $root with tons of things because it was the easy way ?
_____ Update 7th May 2016 _____
OK, I decided against making my theme service globally available when I suddenly was compelled to put my $fileSaver service out on the global scope as well, indicating the my fears of "scope-creep" were valid, instead I decided to implement a <my-injector my-name="$theme" /> directive which allows application designers to import services declaratively, the directive makes the injection target specified in the myName attribute available on the current scope.
It allows app designers to use the service anywhere in the scope like this:
<my-injector my-name="$theme" />
<img ng-src="$theme.logo.url" />
I thought about creating difference convenience directives, e.g. some app designers might find <my-import my-name"$theme" /> more intuitive, but that is a different discussion...
It's not an absolute necessity to avoid rootScope. From the Angular FAQ, with my emphasis:
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
Since your theme seems to be largely data, I say why not use root? If it does contain functions, is it possible to split it? I can't decide that for you, I haven't seen what you're actually trying to do...

AngularJS: Best practices

I don't think this question is considered opinion-based since it is asking about best practices, but at the same time I don't think there are any industry standards for AngularJS best practices, so it's hard to avoid opinions in some cases. In other cases, one way of programming is clearly better than the other. I am not sure which category this question falls under.
I don't think there are any official AngularJS best practices. There are guidelines, and some people have released their own best practices, but I haven't stumbled upon an industry standard.
I have a question about how I'm organizing my modules and the code itself. It feels like I have a lot of small files and too many folders, even though I have broken down the app into common components and core features. It's still a relatively small application, but it's likely to grow.
The biggest question I have was how I should organize my submodules. Currently each submodule is broken down into various files, separating controllers, directives, and services. I was wondering if I should just define them all in one file, and then if the submodule gets too large, break it down again.
For instance, right now I have a module app.buttonToggle, with various files:
buttonToggle.app.js
angular.module('app.buttonToggle', []);
buttonToggleCtrl.js
angular.module('app.buttonToggle').controller('ButtonToggleCtrl', ButtonToggleCtrl);
function ButtonToggleCtrl() ...
...
buttonToggle.js
angular.module('app.buttonToggle').directive('buttonToggle', buttonToggle);
function buttonToggle() ...
...
Instead would it be better to combine them into one file?
buttonToggle.app.js
angular.module('app.buttonToggle', [])
.controller('ButtonToggleCtrl', function() { ... })
.directive('buttonToggle', function() { ... });
What would be the benefit of doing the latter, if any? I like how it uses less code, but is it harder to test?
I recommend using John Papa's style guide - it is what I use to help make these decisions and keep up with and potentially contribute to the best practices. It will help you with this issue. These style guides are becoming very popular to help you with your questions.
In this case, the community agrees you should have one component per file and use a task runner like gulp or grunt to package for shipping.
https://github.com/johnpapa/angular-styleguide
The main benefit here
angular.module('app.buttonToggle').controller('ButtonToggleCtrl', ButtonToggleCtrl);
is that (due to JS hoisting) controller constructor can annotated in readable manner, e.g.
ButtonToggleCtrl.$inject = ['...'];
function ButtonToggleCtrl(...) {
It isn't an issue when automatic annotation is used.
It is also a bit more convenient to debug named functions rather than anonymous ones, though Angular provides meaningful feedback on errors in all cases.
What would be the benefit of doing the latter, if any? I like how it
uses less code, but is it harder to test?
It isn't. All of module components can be tested separately irregardless of how they were defined, as long as their definitions don't contain syntactic errors.

Why using $controllerProvider.allowGlobals() is generally not recommended?

When migrating from Angular 1.2 to 1.3, it's generally recommended that all your controllers are housed inside a module (otherwise they'll break) even though adding one line to the module's config can achieve the same thing:
angular.module('app').config(['$controllerProvider',function($controllerProvider) {
$controllerProvider.allowGlobals();
}]);
But it's not recommended as it may have implications in the future.
Is there another major reason why the latter method is not recommended?
It's to avoid unnecessarily polluting the global namespace, and to reduce the risk that other code, say from some non-Angular plugins, can interfer with yours.
Say you have a controller, MyController in the global scope. Some other bit of Javascript in that page can just set something like
window.MyController = window.alert;
which (depending on when the code runs) can break your Angular app.
When you use global functions as controllers, your functions are going to pollute the global namespace. There could be more chance of collision with other libraries.
That's the reason why in angular 1.3, its recommended to group controllers inside modules. In that way you won't be polluting the global namespace and also in terms of organising code, it's much modular as well. So it helps us to have minimal footprint in the global namespace.

How do I re-use a helper function in Angular testing?

In my unit test (written with protractor) I need to write functions that should be used in several tests in several files (and only in unit tests).
How can I create those functions?
The best solution is to declare the functions in a single file to include in the test files that I need, but I don't know how to do it without creating global variables or global functions.
If you would follow the Page Object pattern, you would not be in a situation like this. All of the functions you need would be tied to page objects, you would have a nice separation of concerns and any changes in the element selection logic would be like a breeze. You can also think about page objects as global libraries available in your tests.
See also how can you apply the pattern using protractor:
Using Page Objects to Organize Tests

Should I worry about creating a module for each controller, service, directive etc

I've noticed some people define a new module for each controller, service, directive etc.
angular.module('controllers.Dashboard',[]).controller(...);
angular.module('controllers.Details',[]).controller(...);
angular.module('controllers.List',[]).controller(...);
However, isn't that a performance issue? I mean: for each controller you create, you also create a new module.
What do you think?
Any performance hit would be incredibly minimal. What you do gain in terms of performance though, is testing speed. Testing can be localized to small modules that don't need to load in the entire application to perform what they need to.
On the code organization side, I personally like the idea of breaking up modules depending on feature not architectural slice. So instead of having a module for controllers, a module for services, etc, create a new module for every new feature/piece of the application. This way you can group together conceptually related controllers, views, services, filters, and so on.
The overhead will be minimal in practice. It is really more of a code organization type issue. On my project we have a FooService, FooController,FooDirectives, BarService...

Resources