Skip to content

Instantly share code, notes, and snippets.

@henrahmagix
Last active August 29, 2015 14:24
Show Gist options
  • Save henrahmagix/e0067ca707297ad952c6 to your computer and use it in GitHub Desktop.
Save henrahmagix/e0067ca707297ad952c6 to your computer and use it in GitHub Desktop.
Performance difference between angular modules taking care of their dependencies or requiring sub-modules that take care of their own dependencies.

Perf test for modular modules

Instructions

For when JSPerf is down, which it is currently.

  • Preserve your console log
  • Type #typical into the url
  • Refresh the browser ten times
  • Average all the times together
  • Repeat for #modular and compare

Why?

For a directory structure like below, init.js registers the app module and so it needs to know about all the dependencies required by the controllers, directives, and services files. This can be hard to keep track of as more and more components are added to the module, each getting its own file but having to place its dependencies in the module initialisation in init.js.

custom/
└── scripts
    ├── controllers
    │   ├── controller-1.js
    │   └── controller-2.js
    ├── directives
    │   ├── directive-1.js
    │   └── directive-2.js
    ├── init.js
    └── services
        ├── service-1.js
        └── service-2.js

In the following example files, init.js must know about controller-1.js's dependency on third-party-library since it requires the use of thirdPartyComponent.

// init.js
angular.module('custom', [
    'third-party-library'
]);
// controllers/controller-1.js
var module = angular.module('custom');
module.controller('MyController', [
    'thirdPartyComponent',
    function (thirdPartyComponent) {
        // ...
    }
]);

But what if init.js only depended on sub-modules, and those sub-modules took care of their own dependencies?

// init.js
angular.module('custom', [
    'custom.controller1'
]);
// controllers/controller-1.js
var module = angular.module('custom.controller1', [
    'third-party-library'
]);
module.controller('MyController', [
    'thirdPartyComponent',
    function (thirdPartyComponent) {
        // ...
    }
]);

Now, controller-1.js can add or remove other dependencies it relies on, and init.js doesn't need to be changed.

Hooray!

Preliminary performance comparisons

Mode-typical: 146.181ms
Mode-typical: 131.293ms
Mode-typical: 201.813ms
Mode-typical: 207.610ms
Mode-typical: 157.997ms
Mode-typical: 151.761ms
Mode-typical: 188.516ms
Mode-typical: 199.562ms
Mode-typical: 159.236ms
Mode-typical: 266.121ms

Average: 181.009

Mode-modular: 156.948ms
Mode-modular: 160.304ms
Mode-modular: 216.025ms
Mode-modular: 182.681ms
Mode-modular: 202.248ms
Mode-modular: 200.069ms
Mode-modular: 142.098ms
Mode-modular: 191.267ms
Mode-modular: 169.965ms
Mode-modular: 169.026ms

Average: 179.0631

Conclusion

Inconsequential performance difference when more modules are registered.

Advantages

  • Easier dependency management
  • Less likely to get errors in unit tests due to missing dependencies
  • Individual components of a module can be used elsewhere without the rest of the module having to be loaded

NB: this test is similar to a minified production site, since there is just one file request to get the custom code.

<!DOCTYPE html>
<html ng-app="app">
<head>
<title>Angular module loader test</title>
</head>
<body>
<script>console.time('Mode-' + window.location.hash.slice(1));</script>
<script src="angular.js"></script>
<script src="modules.js"></script>
<script>console.timeEnd('Mode-' + window.location.hash.slice(1));</script>
</body>
</html>
(function (angular) {
var mode = window.location.hash.slice(1);
var create = function (name) {
if (mode === 'typical') {
angular.module(name, []).factory(name + 'Object1', function () {return {};});
} else {
angular.module(name + 'Factory1', []).factory(name + 'Object1', function () {return {};});
angular.module(name + 'Factory2', []).factory(name + 'Object2', function () {return {};});
angular.module(name + 'Factory3', []).factory(name + 'Object3', function () {return {};});
angular.module(name + 'Factory4', []).factory(name + 'Object4', function () {return {};});
angular.module(name + 'Factory5', []).factory(name + 'Object5', function () {return {};});
angular.module(name, [
name + 'Factory1',
name + 'Factory2',
name + 'Factory3',
name + 'Factory4',
name + 'Factory5'
]);
}
};
var all = [];
for (var i = 0; i < 100; i++) {
all[i] = i.toString();
create(all[i]);
}
var app = angular.module('app', all);
}(window.angular));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment