Speeding Up your Slow Angular 1 App

01 Oct 2016 . . Comments

All experienced developers know Angular 1 is slow and it will take a lot of effort on your part to make it fast. Here, I'll highlight all of my tricks to speed up your Angular 1 app. Some of these are quite general, meaning you can apply them also to Angular 2, to other frameworks you use or other websites you build. First, I'll cover some essential techniques that you must have in order to have a fast Angular app and then I'll make some suggestions.

Essentials

Gzip, Minifiy and Cache bust Everything

Gzipping is the process of compressing your files on your server and sending the compressed file to the user. The user's browser will decompress the file automatically. This is quite easy to do on the server side. If your files don't change it's best to pre-compress the files once, rather than have them requested

Cache Busting allows you to send a updated version of a file to the user even though they already have the old one cached. In order to add file caching to your website you need to add a Cache-Control header setting the expiry time (1 year is fine if you Cache bust). Once the header is set, your user will keep that file until you update and cache bust it or the specified expiry time expires. For Gulp, you can use gulp-rev and gulp-rev-del to create gulp tasks that will rename your files with hashed strings - e.g app.js to app-2124151e.js. Do caching for all your assets except images.

Minification is simply getting rid of unnecessary whitespace and long variables. When minifying an angular app, it's important you match your dependencies with strings as minifying javascript with Uglify can mangle your dependencies. Mangling is when your variable names are changed in order to make the code shorter. It's important to match strings with the dependency name in order to import the appropriate dependency.

Use Angular Batarang to Help Identify and Reduce Watchers

Angular Batarang's performance tab can really help identify what expressions have the most watchers. Once you identify, these expressions you can put two colons in front of your expression like so ::(expression). This is what's called a 1 time bind, it's pretty much saying that the view is a read-only value, it will never change unless the scope of the component is destroyed. Thus, it will just stay there if your directive/component or view does not change.

Remove Non Angular Events on Scope Destroy

If you use Event Listeners without using Angular, such as document.addEventListener, you must unbind the listener when the scope is destroyed. Unbinding these events will reduce the overall load on your app and thus speed up your code.

Lazy Load as Much as Possible

Lazy loading allows you to load modules and assets after the initialization/boostrap of the Angular app. Currently, the only solution for Angular 1 is ocLazyLoad. OcLazyLoad allows you to lazy load routes, JS libraries, templates, and even css. Luckily if you're starting an Angular 2 project, lazyloading is built in, use it. Some libraries that are a must to lazy load - Angular Google Maps - Stripe - Flickity - Any UI libraries that you only use on one page - Validation libraries

One-Time Bind as much as possible

In addition to finding the expressions in Batarang, you need to always think one-time bind first when developing. Use one time binds and 1.5+ components as much as possible. These components have one time binds built in and are efficient in handling the isolate scope.

Disable Angular Debugging mode when in Production

angular.module('myApp')
      .config(['$compileProvider',function($compileProvider) { $compileProvider.debugInfoEnabled(false);
      }])
 

Optional

Speed up Http Requests

Use:

mymodule.config(function ($httpProvider) {
  $httpProvider.useApplyAsync(true);
});
 

This will make it so that your http requests all fire within the same $scope.applyAsync(), meaning that it will execute less code and iterations in the digest cycle.

Delete unused modules from external libraries

Fork an npm module in your own git repo and trim it down. I do this with unnecessarily large libraries, such as Angular Google Maps (182kb!!). You can get rid of a good 50kb or more when you trim out things you don't use like street view, Also, frameworks like Angular and Angular UI Bootstrap allow you to import the modules individually. This is a lot easier than going through the code line by line.

Lazy Load Images

In addition to lazy loading your modules and assets. It's important to only load the images the user sees on the page. There are quite a few pure javascript solutions for this. The best I've found for performance (if you can afford it) is Cloudflare's Mirage. Mirage also uses Javascript and will lazy load any images that appear. Other Angular driven solutions involve watchers which can be a performance cost. However, that extra watcher will ensure that your initial page load is still a lot faster.

Compress Images and Assets with Imagemin and/or Kraken.io

The node imagemin plugin (search gulp-imagemin or grunt-imagemin) allows you to compress svgs, icons, and images through minification. You can also use professional compression services such as Kraken.io to better compress your assets. This is perhaps the most important thing for initial page load times for mobile.

If you notice anything wrong with these snippets or disagree with my advice, please let me know. Happy Coding.

Cheers, Evan Gillogley