Montag, 10. Oktober 2016

Performance - AngularJs / JavaScript + (Cordova) - Do's don'ts

graphefruit2
After developing a huge Cordova app with much performance struggles I decided to make my own blog-post about all issues which crossed my way.
So I agree that there are massive blogs/website outsides where already many information are provided but to be honest, I needed to crawl 40-50 pages to get all information about performance, aswell as my own experience.

So what will this post cover?

  1. AngularJs ✔
  2. JavaScript ✔
  3. CSS / HTML ✔
  4. Angular-Material / Framework performance optimizing ✔
  5. Cordova (iOS, Android, Windows Phone 8.1/10 no UWP) ✔
  6. Browser performance check - Upcoming
  7. Device performance-check - Upcoming
  8. Awesome guides / related links  ✔

Maybe I gonna exclude some points to smaller pages but at the start I try to cover everything here.

AngularJs

So after there are very many AngularJs versions outside, in my topic i'll cover the things I encountered with Angular 1.5, so if you've 1.3 or lower you maybe need to get some polyfills/shims.

On many pages you'll read about the standard problems
  • ng-repeat ✔
  • filter / orderby ✔
  • bind-once ✔
  • use latest libraries ✔
  • cache data ✔
But there are still some more to go:
  • AngularJs-loading-time ✔
  • $q ✔
  • $http ✔
  • $timeout / $interval ✔
  • requestAnimationFrame ✔
  • debounce ✔
  • AngularJs config ✔
  • animation ✔
  • Gulp - Minimize Code, CSS / Cache Templates ✔
  • dependency injection ✔
  • use-strict ✔
  • console.log ✔
  • watchers / $intervals ✔
  • minimize watchers ✔
  • ng-template ✔
  • ng-style instead ng-class ✔
  • ng-if instead ng-show ✔

Before we start with all the topics, just let me say: I didn't pay much attention to animation, because they cause big problems, so I tried to disable / remove them wherever possible.

AngularJs-Config

So the easiest way to get some more performance is to change the startup configuration in your AngularJs project.

1
2
3
4
5
6
7
8
.config(['$httpProvider','$compileProvider', function ($httpProvider,$compileProvider) {
 $httpProvider.useApplyAsync(true);
 $compileProvider.debugInfoEnabled(false);
//https://docs.angularjs.org/api/ng/provider/$compileProvider
//upcomming with 1.5.9?
$compileProvider.cssClassDirectivesEnabled(false);
$compileProvider.commentDirectivesEnabled(false);
}])

$httpProvider.useApplyAsync: Combine multiple $httpRequests-Digests to one.

$compileProvider.debugInfoEnabled: Disable AngularJs information binding
Care you cant use now angular.document(...).scope()
If you need to access the root element, store your root-element outside
var rootEl = $scope.$root
$compileProvider.cssClassDirectivesEnabled: Upcoming
$compileProvider.commentDirectivesEnabled: UpComing

If some libraries use the $animateProvider, but you don't use it internal, disable the animation for this libraries aswell:

1
$animateProvider.classNameFilter(/ignore-animate/);

AngularJs Run

1
2
3
4
.run(['$animate', function ($animate) {
    //Performance, disable all animation
    $animate.enabled(false);
}])

Strict DI-Mode:

Normaly many developers write "incorrect" AngularJs-Code because they don't care/know about the strict dependency injection, thats why you can't minimize your AngularJs-Code.

1
2
3
angular.bootstrap(document, ['myApp'], {
  strictDi: true
});

So after using script dependency injection we can't write:
1
2
3
4
.controller('myController',MyController)

function MyController($scope)
{...}
anymore.

We need to write it with braces now:
1
2
3
4
.controller('myController',['$scope',MyController])

function MyController($scope)
{...}

If you're doing this since the start, you will never get into any troubles.

Use-Strict

In some points I noticed different performance when using:

1
"use strict;"
on top of any of my own script files.

$q

After using $q.defer everywhere I tried to check if its realy needed.
The problem which occurs is, that every time a $q.resolve or $q.reject is executed, AngularJs performance a digest-cycle, so everything on your page will be checked and by need updated.

If you're using the $q-object you'll gain some positive effects: You don't need to care about the $scope.$apply, because it will trigger anyway, but sometimes you don't even need to tell AngularJs yet that something has changed.

$http

$http triggers like $q an own digest-cycle, if you got multiple $http-requests performing, you can combine them like shown above: $httpProvider.useApplyAsync(true), but if you don't need this, write your own XHR request or use jQuery.ajax.

$timeout, $interval

Like with $q the $timeout and $interval will trigger by default an digest-cycle
So why should you need:

1
2
3
4
$interval(function ()
{
//Check if something is ready here
},1000)

If you could do this:
1
2
3
4
setInterval(function ()
{
//Check if something is ready here
},1000)

Every $interval triggers an digest-cycle.
If you need to update an HTML-Element the first approach would be fine, but if you're HTML doesn't need to be affected just leav it with the second approach.

The same goes for $timeout and setTimeout, stop wasting digest-cycles which are not needed.

AngularJs-Loading-Time/jQuery

I found a simple article which speeds up the loading time by AngularJs library:

1
2
3
4
5
6
7
8
 //https://ng-perf.com/2014/10/24/simple-trick-to-speed-up-your-angularjs-app-load-time/
    if (jQuery) {
        var originalFn = $.fn.data;
        $.fn.data = function () {
            if (arguments[0] !== '$binding')
                return originalFn.apply(this, arguments);
        };
    }
Just put this after you've loaded jQuery.
By the way: If you don't need jQuery don't even include it.

Console.log

If you're using logging inside your app, and you don't use $log disable the console.log while on production.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (isProduction) {
    /**Disable console in apps **/
    try {
        if (typeof(window.console) != "undefined") {
            window.console = {};
            window.console.log = function () {
            };
            window.console.info = function () {
            };
            window.console.warn = function () {
            };
            window.console.error = function () {
            };
        }

        if (typeof(alert) !== "undefined") {
            alert = function () {
            }
        }

    } catch (ex) {

    }
}

requestAnimationFrame

After many insights I've seen that using requestAnimationFrame instead of setTimeout is most times more efficiency.
- If you need to wait 1 or 2 seconds then you should use setTimeout
- If you just need to have a short delay till the next animation-frame, use requestAnimationFrame.

Why should I use the requestAnimationFrame?
-> You wait till the browser needs to paint anyway, so you will grab into this event, instead of saying the browser he needs to paint, and then paint again because the requestAnimationFrame.

debounce

If you've got events which trigger very often like a scroll-event, you should think about using debounce.

What is debounce doing?
Debounce sets an timeout, which will be overwritten if the user interacts faster then the given timeout, after the timeout is hit, the code will be executed.

So instead:


1
2
3
4
$("#element").scroll(function ()
{
console.log("User scroll");
})

use:
1
2
3
4
5
6
7
var debounceScroll = debounce(function (event) {
 //your event
}, 350);
searchProducts.bind('scroll',function ()
{           
 debounceScroll(event);
});
Reference to debounce: http://stackoverflow.com/questions/24004791/can-someone-explain-the-debounce-function-in-javascript

Also you can evade digest-cycles with this trick.

animation

Like told already at the beginning, I'm not a big fan of animation or something like this, because I needed to support old phones (android 4.1 and iOS7 aswell as windows-phone 8.1) which doesn't realy work well with animation).

So my conclusion for animation: Disable wherever possible and don't use.
Have a look on AngularJS config.

watchers / $intervals

Often you attach an watcher or create an $interval but you forget to destroy this elements on $destroy so don't forget to unregister this elements.

1
2
3
4
5
6
var listener = scope.$watch(..)
var interval = $interval(function(){..});
scope.$on("$destroy",function handleDestroyEvent() {
 listener();
 $interval.cancel(interval);
});
Remember: if you don't need $interval, use setInterval

ng-repeat

Maybe you read it somewhere else: ng-repeat is good and bad in once.
Why is ng-repeat so bad?
Ng-repeat lets you create very easily less or more complexe dom structures:


1
2
3
4
5
6
<div ng-repeat="user in users">
   <div>{{user.forename}}</div>
   <div>{{user.lastname}}</div>
   <div>{{user.age}}</div>
   <div>{{user.city}}</div>
</div>

So in this sample we see an simple repeat for a user, lets pretend we got 100 users, which will create 500 div-elements
Normaly chrome or firefox won't get hurt, but IE will squeal.

If you can, use this:

  1. Load on demand
  2. Page data
  3. Limit data

One realy good reference, ishttp://blog.mgechev.com/2015/03/02/immutability-in-angularjs-immutablejs/ this way you create an array in a complete new way.
Sadly I couldn't use this version, because my development was to advanced.

angular watchers

So after we got this 500 div-elements, we also got 401 watchers which will be checked everytime a digest-cycle will be triggered.

Here bind-once comes into the game:


1
2
3
4
5
6
<div ng-repeat="user in users">
   <div>{{::user.forename}}</div>
   <div>{{::user.lastname}}</div>
   <div>{{::user.age}}</div>
   <div>{{::user.city}}</div>
</div>

After this we got just 1 watcher left for our users array, because bind-once, like the word says: Bind the element value once and then forget it.

Reference for older AngularJs versions: https://github.com/Pasvaz/bindonce
If you're using AngularJs 1.3 or above, you already have this feature implemented.

If you want to eliminate the last watcher aswell, you can bind-once the users-Array aswell:

1
2
3
4
5
6
<div ng-repeat="user in ::users">
   <div>{{::user.forename}}</div>
   <div>{{::user.lastname}}</div>
   <div>{{::user.age}}</div>
   <div>{{::user.city}}</div>
</div>

Care:
If your user-Array will change on the fly, the Dom won't be updated, so rather don't bind-once the array or include this solution: http://www.codelord.net/2016/04/21/angular-performance-updating-bind-once-elements/

watcher count

Sometimes you don't even know how many watchers/listeners you've already on your page, have a look on point 4 here: http://stackoverflow.com/documentation/angularjs/1921/profiling-and-performance/6270/7-simple-performance-improvements#t=201610101219137928011
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
(function() {
    var root = angular.element(document.getElementsByTagName('body')),
        watchers = [],
        f = function(element) {
        angular.forEach(['$scope', '$isolateScope'], function(scopeProperty) {
            if(element.data() && element.data().hasOwnProperty(scopeProperty)) {
                angular.forEach(element.data()[scopeProperty].$$watchers, function(watcher) {
                watchers.push(watcher);
                });
            }
        });

        angular.forEach(element.children(), function(childElement) {
            f(angular.element(childElement));
        });
    };
 
    f(root);
 
    // Remove duplicate watchers
    var watchersWithoutDuplicates = [];
    angular.forEach(watchers, function(item) {
        if(watchersWithoutDuplicates.indexOf(item) < 0) {
            watchersWithoutDuplicates.push(item);
        }
    });
    console.log(watchersWithoutDuplicates.length);
})();

This code will log the count of all watchers, try to remove as much as watcher's as possible, so AngularJs digest-cycle will get faster and more perfomant.
Also you can set a breakpoint and have a look into watchersWithoutDuplicates.

filter/sort

If you're using filter or orderBy with your ng-repeat you should exclude this code from html and insert it into your controller:

1
2
$scope.normalArray = [1,2,3,4,5];
$scope.filteredArray = sort....

1
2
3
<div ng-repeat="entry in filteredArray">
...
</div>

Why is this important? The filter or orderBy is checked every digest-cycle , so rather do it inside your code on startup or on button-press.

custom attribute-directives inside ng-repeat

Sometimes you need to use some attribute custom directives inside your ng-repeat, but every custom directive has (mostly) an own watcher, which will be executed on every digest-cycle.
Specially this custom directive is called for every element which is repeated and interpreted, so its much faster to do it inside your controler.

Date sample: 

Some more points you can see here: http://stackoverflow.com/documentation/angularjs/1921/profiling-and-performance/6270/7-simple-performance-improvements#t=201610101219137928011


1
2
3
<div ng-repeat="log in logs">
{{log.DATE | date:["HH:MM:SS"]}}
</div>

Instead of converting the date to the right format by an directive, format it already by building the array entry:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
$scope.logs = [];
function buildLogs()
{
  for (var i=0;i<100;i++)
  {
    $scope.logs.push({
      ID:i,
      date: formatDate("...")
    }
  }
}
function formatDate(_date)
{
 //Format here...
 return "10:11:12"
}

$scope.logs=buildLogs();

So maybe you'll get some overhead in your controller, but the performance will be very thankful.

Remember: Everything you can calculate in your controller, do it inside, and not outside on html, because the HTML will need to interpret it again.

virtual-scroll

If you need to display 100+ elements with ng-repeat, you should think about virtual scroll
Its sometimes tricky to setup, and often you need a specific height for your elements, but the performance will be much faster.

Specially on Windows-Phones you should use this alternative.

Gulp - Cache, Minimize

Because AngularJs is so easy to use, you easily forget to cache and minimize your templates.
Its a bit overwhelming at start but you'll get used to it fast.
To cache you'r templates and to minify your application I've a small script which can be executed by gulp.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var minifyHtml = require('gulp-minify-html');
var ngTemplate = require('gulp-ng-template');
var cleanCSS = require('gulp-clean-css');
gulp.task('js', function () {
    return gulp.src([       
        './scripts/yourFiles.js'])
        .pipe(uglify())
        .pipe(concat({path: 'app.min.js', stat: {mode: 0666}}))
        .pipe(gulp.dest('./scripts/dist'));
})
gulp.task('templates', function () {
    return gulp.src('./templates/**/*.html')
        .pipe(minifyHtml({empty: true, quotes: true}))
        .pipe(ngTemplate({
            moduleName: 'templates',
            standalone: true,
            filePath: 'templates.js',
            prefix: 'templates/',
        })).pipe(gulp.dest('./scripts')); // output file: 'dist/js/templates.js'
})
gulp.task('css', function () {
    return gulp.src([
        './css/yourCss.css',     
  ])
        .pipe(cleanCSS({compatibility: 'ie8'}))
        .pipe(concat({path: 'app.min.css', stat: {mode: 0666}}))
        .pipe(gulp.dest('./css'));
})
gulp.task('default', ['templates', 'js','css'])

Add your own *.js, *.html or *.css files inside this script and run it.
If needed change the gulp.destination folder.
Care: You need to install npm, gulp and the dependencies

Don't forget to include 'templates.js' inside your gulp.js task

After this script all templates will be cached to one file: templates.js, this one can be included now

1
angular.module('app', ['templates'])

Care: You need to execute the gulp command twice, because on first run, the templates.js won't be existing - I know its uncool, but I didn't want to waste my time to build this task synchron.

Also you'll get one app.min.css file which inherits all css files.

Now you're app/website just needs to load 3 files:
  1. index.html
  2. app.min.css
  3. app.min.js
instead of 30-50 files.

ng-template

Maybe you have already seen some solutions where you insert your templates as a script tag.

1
2
3
4
5
6
<script type="text/ng-template" id="/tpl.html">
  Content of the template.
</script>

<a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
<div id="tpl-content" ng-include src="currentTpl"></div>
Avoid this topic completly because it will bring big performance challanges, specially on IE.

ng-style instead ng-class

So often you need to style your element's when active or disabled. If possible use ng-style instead of ng-class, because ng-style will be much faster.
Reference: https://ng-perf.com/2014/10/29/tip-3-ng-style-is-much-faster-than-ng-class/

ng-if instead of ng-show

If you need to show or hide elements, and you don't need them in DOM, use ng-if instead of ng-show.
Ng-if destroys all watchers/listeners and your DOM will be clean.
Reference: http://www.codelord.net/2015/07/28/angular-performance-ng-show-vs-ng-if/

cache data

This point is rather mentioned for mobile-apps instead of websites.
Often your app needs data from a backend and normaly a $http.get will do everything.
But if the user revists the page after some seconds, the data would be still the same, so why not cache them?
I've build a custom solution to cache my data and write them down to filesystem, if you don't need to cache persistent have a look into the $cacheFactory.
There will be more tools outside, choose the one which you're most comfortable with.

Care: Often the different Phones/Tablets doesn't support the same methods, so you need to get polyfills/shims, or you just use the plain old filesystem like I did ;)

Latest libraries

So like everyone else would tell: Use the latest library if possible.

JavaScript

Some points in pure JavaScript aswell.

For

Most of the time you're using loops like:
1
for (var i=0;i<array.length;i++)

instead write:

1
2
var arrayLength = array.length;
for (var i=0;i<arrayLength ;i++)
Because every time the array.length will get interpreted in the first sample. If you're using a big array, it can take up some time combined.

Cache Elements

Instead of claim the reference each time, just cache the element:
1
2
3
document.getElementById("ele").style...
document.getElementById("ele").style...
document.getElementById("ele").style...

better solution:

1
2
3
var el = document.getElementById("ele");
el.style...
el.style...

Special treatments

After digging in the performance-console on Chrome, I've found a funny code point on my side:

Solution 1: 80 Objects - 50 to 60 ms
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var decodeHTMLEl = document.createElement("textarea");
function decodeHtml(html) {
   if (!html)
   {
      html ="";
   }
   decodeHTMLEl.innerHTML = "";
   decodeHTMLEl.innerHTML = html;
   return decodeHTMLEl.value;
}

Solution 2: 80 Objects - 30-40 ms

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var decodeHTMLEl = document.createElement("textarea");
function decodeHtml(html) {
   if (!html)
   {
      html ="";
   }
   //decodeHTMLEl.innerHTML = "";
   decodeHTMLEl.innerHTML = html;
   return decodeHTMLEl.value;
}

So not clearing the innerHTML to empty, is giving 20ms more.
I could repeat this timings multiple times, sometimes it would be even faster then 30 ms.

So this isn't a normal performance point, but rather showing you that some special things can speedup your code as well.

There are some more points to discover, maybe I'll add them, but there are many articles outside which already wrote about this points.

CSS / HTML

CSS / HTML is slow? Yes even here we can do some optimizing.

CSS

The newest frameworks/solutions offers data-attributes, and with HTML5 we also can access HTML-5 attributes inside our css files.
This looks realy nice but the truth is, it doesn't play well with the performance.

Custom-Attributes

Instead of using data attributes like: 
1
2
3
4
5
6
7
<style>
[width-100]
{
   width:100%
}
</style>
<div width-100></div>

write:

1
2
3
4
5
6
7
<style>
.width-100
{
   width:100%
}
</style>
<div class="width-100"></div>

Specially IE will thank you for this.

Also selectors like :after, :not, :first, :last are not very performant, try to use them as less as possible.

Shadows

Don't use shadows, use borders.

Border-Radius

Don't use border-radius if not needed.
Reference: http://wijmo.com/blog/fix-flexgrid-scroll-performance-in-ie-with-this-one-weird-trick/

Big css

Avoid big CSS-Files whenever possible (have a look into the framework section in this topic)

HTML-5-Elements

With HTML-5 we can create own elements like:

1
2
3
4
5
6
7
<style>
myElement{
    width:100%
}
<myElement>
Hello
</myElement>

write:

1
2
3
4
5
6
7
<style>
myElement{
    width:100%
}
<div class="myElement">
Hello
</div>

In some cases its usefull to use the new names, but if not needed, rather fall back to classes.

Animation

What about animation? Like already told above, I don't use them, and everywhere possible I disable or remove them.
But if you realy need to have animation, use animation in your CSS instead inside your JavaScript.
There is also a new property will-change which will help to make animation better.

HTML

Ok here's not realy much we can talk about like we not already read in the CSS-Section.
But try to keep your HTML as clean as possible from the startup.

For what you need

1
2
3
4
5
<div>
   <div>
     Test
   </div>
</div>

If you can write:

1
2
3
<div>
Test
</div>

Angular Material / Frameworks

After using Angular-Material inside my application I had much problems with performance.
The points I found out, can be assumed in other frameworks aswell.

Disable animation, lower css (if possible)
- https://github.com/angular/material/issues/8329
- https://github.com/angular/material/issues/8218

After this changes take much into account, I still needed more performance, so I grabbed into the framework myself,

Lower css

angular-material.min.css:
This css had 391 KB, after my changes, the css was 53 KB big
16959 vs 2500 lines of css code.

theme.css
After I disabled the automatic theme generation (which was injected on application start - for IE it took years...)
This css had 928 KB, after my changes the css was 7 KB big.
22435 vs 287 lines of css code.

So what I did was realy painfull but it worked wonders:
  1. Remove uneeded components
    E.g. I didn't use "md-chips" so I removed all css code for md-chips
  2. They had different stylings
    Md-hue-1, Md-hue-2, Md-hue-3.
    After I used my own styles for all components, I could remove all stylings 
  3. I removed every animation / transition
Like said, its realy painfull, but it worked out, even on an iPhone 6S the performance was more noticeable, so IE was happy aswell.

Use own elements

Angular-Material for example has a component <card> every card element was running through the whole library for just an div with a little bit of styling and text inside.
Solution:
Remove all <card> and for this write: <div class="card">

Like the css changes, this isn't cool.

Conclusion: Do you realy need a complete big framework for your requirements?
If no, use a simple styling framework with flex-boxes e.g. or write your own simple framework.

Before I  get rage posts below this topic:
Angular-Material is a super framework which is not bad.
The only point why I'm writing this is because I needed more performance cause of older devices and old browsers (IE 10 e.g.)

Cordova

After my app was developed cross-plattform for iOS, Android and Windows-Phone here are some hints:
  1. Android
    To support old android versions and to get better performance try crosswalk
  2. iOS
    In iOS you can use crosswalk aswell, I didn't test it yet, but the standard webview performance was powerfull enough.
  3. Windows-Phone
    To develop Windows-Phone apps, you need a shim to insert dynamic javascript
    Reference: https://github.com/Microsoft/winstore-jscompat 
    Here's my index.html injection:
  4.  1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    <script type="text/javascript">
    /**IE10/IE11 fix for wrong viewport **/
    if (navigator.userAgent.match(/IEMobile\/10\.0/) || navigator.userAgent.match(/IEMobile\/11\.0/) || navigator.userAgent.match(/Windows Phone/)) {
    
     var msViewportStyle = document.createElement("style");
     msViewportStyle.appendChild(
       document.createTextNode("@-ms-viewport{min-width:auto!important;width:auto!important;}")
       //wp10 fix
       //document.createTextNode("@-ms-viewport {  width: device-width;height: device-height; }")
     );
    
     document.getElementsByTagName("head")[0].appendChild(msViewportStyle);
    }
    /*Polyfill for IE*/
    if (!String.prototype.startsWith) {
     String.prototype.startsWith = function (searchString, position) {
      position = position || 0;
      return this.indexOf(searchString, position) === position;
     };
    }
    //Fix for not Windows Mobile Apps.
    if ("undefined" === typeof MSApp) {
     MSApp = {};
     MSApp.execUnsafeLocalFunction = function (func) {
      try {
       func();
      } catch (ex) {
      }
     };
    }
    
    
    var isDesktop = !navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|IEMobile)/);
    var html5Mode = true;
    if (window.location.href.toString().substring(0, 4) != 'http') {
     //Filesystem.
     html5Mode = false;
    }
    var isWeb = true;
    var baseurl = "";
    if (html5Mode == true) {
     //Set translation language
    
     window.onload = function () {
      angular.bootstrap(document, ["app"],  {strictDi: true});
     };
    
     MSApp.execUnsafeLocalFunction(function () {
      //base href needed for subfolder working with angular.
      document.write('<base href="' + '/www/' + '" />');
     });
     baseurl = '/';
    }
    else {
     isWeb = false;
     baseurl = window.location.href;//"file:///android_asset/www/";
     if (baseurl.indexOf("index.html") > -1) {
      baseurl = baseurl.substr(0, baseurl.indexOf("index.html"));
     }
     if (baseurl.lastIndexOf("/") != baseurl.length - 1) {
      baseurl += "/";
     }
     MSApp.execUnsafeLocalFunction(function () {
      //base href needed for subfolder working with angular.
      document.write('<base href="' + baseurl + '" />');
     });
    }
    </script>
    
    Windows-Phone has some problems: 
      1. You need to set the right width/height with the @ms-viewport
      2. You want the shim and android/iOS working together, that is why I created an own "MSApp.execUnsafeLocalFunction"-Wrapper

      When creating an UWP-Windows-Phone-App you don't need the shim.
Cordova doesn't support HTML-5 Url's.

If you don't want to care about all these problems, use e.g. Ionic, which build a complete own solution: 

Ionic:
Android 4.1+
iOS 7+
Windows-Phone: Not Supported.

V2 - Typescript: http://ionicframework.com/docs/v2/
Android 4.4+ (With crosswalk you can support 4.1+ - already tested it)
iOS 8+
Windows: UWP supported.

There are some more frameworks for complete cordova-apps, but I've just used ionic yet

Awesome guides

All this guides were read by me and nearly everything was taken into account by writing this big post.
Thanks to all of these guides which helped me out, and where very important!
There is no ranking about the links following up.
  • http://bahmutov.calepin.co/improving-angular-web-app-performance-example.html
  • http://wijmo.com/blog/fix-flexgrid-scroll-performance-in-ie-with-this-one-weird-trick/
  • http://calendar.perfplanet.com/2013/the-runtime-performance-checklist/
  • https://www.html5rocks.com/en/tutorials/speed/high-performance-animations/
  • https://tech.small-improvements.com/2013/09/10/angularjs-performance-with-large-lists/
  • http://de.slideshare.net/nirkaufman/angularjs-performance-production-tips
  • https://medium.com/swlh/improving-angular-performance-with-1-line-of-code-a1fb814a6476#.xegs48x3b
  • https://benfrain.com/improving-css-performance-fixed-position-elements/
  • https://benfrain.com/css-performance-revisited-selectors-bloat-expensive-styles/
  • https://www.airpair.com/angularjs/posts/angularjs-performance-large-applications
  • http://blog.mgechev.com/2015/03/02/immutability-in-angularjs-immutablejs/
  • https://ng-perf.com/2014/10/29/tip-3-ng-style-is-much-faster-than-ng-class/


So far, I gonna update this blog in the next days.
Any questions, feedback? Leave me a comment.

0 Kommentare:

Kommentar veröffentlichen

Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.

Powered by Blogger.

Follower