Analyze and optimize the performance of the censhare Web frontend.
AngularJS
Tutorial
Before making any performance related optimisations in angularJS, please make sure to first have a look on the tutorial below Speeding up AngularJS apps with simple optimizations.
censhare Specific Tips
Here will be analyze a few tips which are special for our application:
If you use
$compile
,$controller
and$http
to fetch templates, be aware that$compile
returns a function which can be "reused" to instantiate the same template multiple times. Then, parsing is avoided entirely but the on the first usage. It's worth mentioning that the dynamic controller is performing this same way as well, hence the item renders are benefiting from such kind of optimisations too.$timeout
shouldn't be called with the third parameter astrue
(or omit the third). It triggers a global apply, which will digest everything.If you use a 'registerChangeListener', the listener is executed in the "angular" word and hence a digest is performed. The
csServices
it's optimized in a way that it will avoid triggering a global digest, instead it will trigger a digest on scopes involved. You can use theregisterNativeChangeListener
to avoid the digest. Be careful here as you will have to take care of updating the UI by yourself in these callbacks.Preloading modules - When in need (but should not be used too often), you can tell the client to load modules which will required later on. For example: in wizards, when the next wizard step it's going to display a layout manager, you can request the module loader to load the corresponding module of the layout manager one step before the layout manager is actually shown. If a timeout is used in the controller of the previous step (see 2.), you can let the client load the needed information for the next step, while the user is filling out a form. Then when pressing "next" the next step will be loaded faster, because JS and angular templates are not needed to be loaded. You must make sure in such optimisations that the user experience is not slown down. (Such optimisation was applied on the login frame and it saved ~750ms after the click to "login", which was ~25% of the time required to show the home screen after the login).
Advanced Tips
Maybe someone finds this following slideshow useful as well: (by Klemen Oslaj) Slides
How to use $timeout
In our current client the $timeout method of angular is used in many places to trigger asynchronous tasks later.
Therefore, we came up with some guidelines to ensure the $timeout is used in our project correctly and only when it makes sense.
When possible, avoid using
$timeout
at all. It should be only used when there are no other alternatives (that is not always possible). It is typically better to find a way to react upon a change somehow by using a$watch
, or by registering yourself as a change listener to an observable, or use a promise result, etc.$timeout
is always fragile, because the timeout time to be used is questionable. The timeout time depends on the speed of the machine that the client is running on. When the goal is to execute something when the view is updated, then the timeout time should be 0.If you are forced to use $timeout for some reason, please be aware that a) You can use it with
$timeout(function () { ... }, xx, false)
b) and the$timeout(function () { ... }, xx, true) === $timeout( function () { ... }, xx) // true is the default
https://docs.angularjs.org/api/ng/service/$timeout
As you can see, the third parameter makes it possible to avoid a global scope apply call. (This call invalidates all angular scopes in our application and digests them. This is an expensive operation, because in our application we have a lot of data in our scopes. (E.g: The results of all open searches. The digest takes multiple 100 milli seconds). When the application is running, this is not a big issue, but in a lot of cases the calls are also fired during the startup of a page. That is why our initial page impression as well as switching between different pages may be influenced negatively by calling $timeout
with a true as third parameter.
If your timeout callback does not require a view invalidation (you just manipulate the DOM directly, your interaction with the server, you are using observables, etc.) you should give the version 2a) a try.
Angular
- Use
OnPush
to change detection - Disable space preservation
- Disable encapsulation when not needed
No direct DOM manipulations, prefer Angular templates
- If absolutely necessary, use renderer2
Use
ngZone
with runOutsideAngular for frequently fired async events:ngZone.runOutsideAngular(() => { element.addEventListener('mousemove', this.mouseMoveHandler); });