Web Application Performance
Pillars of Web Performance
Network | Compute | Render
Network
Minimize payload size + round-trip times (RTT)
Turn GZIP on the server
Compress served resources
Test GZIP enabled: Open chrome dev tools -> Network -> Select Resource -> Header. Make sure you have Content-Encoding:gzip in the header.
Enable GZIP on Apache
mod_deflate configuration for Apache 2.x:
<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
# Don’t compress
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
#Dealing with proxy servers
<IfModule mod_headers.c>
Header append Vary User-Agent
</IfModule>
</IfModule>
NodeJS + Express
var express = require('express');
var app = express();
app.use(express.compress());
var oneYear = 31557600000;
app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
app.listen(process.env.PORT || 3000);
Using a CDN - traditional pattern
Using a CDN - with yepnope
Asynchronous conditional resource loader
Using a CDN - with require.js
JavaScript file and module loader
requirejs.config({
paths: {
jquery: [
'//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min',
'../js/lib/jquery'
]
}
});
//Later
require(['jquery'], function ($) {
});
Images
Over 60% of typical page sizes are images
Use proper image compression
- GIF: animation or transparency (IE6)
- PNG: drawing or if a wide color range is needed with transparency
- JPEG if the image is a photograph.
- WEBP - new standard from google (limited support)
Pick whichever compresses best per image!!!
Tools are available that perform further, lossless compression on JPEG and PNG files, with no effect on image quality
- JPEG: jpegtran or jpegoptim
- PNG: OptiPNG or PNGOUT
- You can use page speed :-)
Create SPRITEs to minimize round trips
Responsive Design?
One size does not fit all!!!
But, there are no perfect solutions
Images in responsive design
Minify JS/CSS/HTML
Downloading smaller files...
Remove duplicate
JS/CSS/HTML/Anything...
Use good modular design practices
Omit the protocol from embedded resources (http:, https:)
<!-- Bad -->
<script src="http://www.mysight.com/js/foo/bar/main.js"></script>
<!-- Better -->
<script src="//www.mysight.com/js/foo/bar/main.js"></script>
<!-- Best (if hostname is the same, use a relative path) -->
<script src="/js/foo/bar/main.js"></script>
Omit optional tags
Not recommended
<!DOCTYPE html>
<html>
<head>
<title>Sample</title>
</head>
<body>
<p>Hello World</p>
</body>
</html>
Recommended
<!DOCTYPE html>
<title>Sample</title>
<p>Hello World</p>
Omit type attribute for styles and scripts
<!-- Bad -->
<link type="text/css" rel="stylesheet" href="/foo/style.css"/>
<script type="text/javascript" src="/foo/main.js"></script>
<!-- Good -->
<link rel="stylesheet" href="/foo/style.css"/>
<script src="/foo/main.js"></script>
Use shorthand CSS where possible
/* Not recommended */
border-top-style: none;
font-family: palatino, georgia, serif;
font-size: 100%;
line-height: 1.6;
padding-bottom: 2em;
padding-left: 1em;
padding-right: 1em;
padding-top: 0;
/* Recommended */
border-top: 0;
font: 100%/1.6 palatino, georgia, serif;
padding: 0 1em 2em;
Write compressible Javascript
- Avoid global variables (put code in closure)
- Make global variables local (window, undefined, etc)
- Avoid using 'this' too often, assign to 'self' or 'that'
- Study JQuery...
Don't freeze the UI
- 1 thread = if JS is running, nothing else is happening
- Use setTimeout to allow the UI to update when performing long computations
- Use Web Workers if available for long JS work
UI frozen by JS execution
My utility for long-running JS code
Defend against stack overflow and UI blocking
Closures are not cheap
- Reuse functions
- Avoid array.forEach(), JQuery.each(), Y.each(), dojo.forEach, ... when possible
Automatic Garbage Collection
- Runs whenever it wants
- Minimize creation/destruction cycles
- May want to use an object pool
Repaint - also known as redraw - is what happens whenever something is made visible when it was not previously visible, or vice versa, without altering the layout of the document.
-Mark 'Tarquin' Wilton-Jones
When Repaint?
- Change visibility
- Formatting style change (colors, borders, etc)
- When reflow occurs
-Nicholas Zakas
Reflow is the process by which the geometry of the layout engine's formatting objects are computed.
-Chris Waterson
When Reflow?
- Initial page load
- Browser window resize
- DOM nodes added/removed
- Layout style applied
- Layout information retrieved
-Nicholas Zakas
Put stylesheets at the top
Put scripts at the bottom
Don't block page rendering
Reduce DOM elements
Fewer bytes to download
Faster browser performance
Minimize Reflows!!!
Touch the live DOM as little as possible
Example 1 - bad performance
Example 1 - better, but still bad
Browsers are intelligent
Browser has to give you the most up-to-date value when calling:
- offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- getComputedStyle(), or currentStyle in IE
Avoid calling these in a loop where css is changed!
Avoid forcing dom reflow
display: none or use DocumentFragments (document.createDocumentFragment())
HTMLCollection Objects - ARE LIVE!
document.images
document.forms
getElementsByTagName()
getElementsByClassName()
-
Nicholas Zakas
Infinite loop!
var divs = document.getElementsByTagName('div'), div;
for(var i = 0; i < divs.length; i++) {
div = document.createElement('div');
divs[i].appendChild(div);
}
HTMLCollection Objects
- Avoid if possible
- Copy to a an array if used often
- Use JQuery, which returns a JS array that is not live
CSS Selectors - use them efficiently
- ID, e.g. #header
- Class, e.g. .promo
- Type, e.g. div
- Adjacent sibling, e.g. h2 + p
- Child, e.g. li > ul
- Descendant, e.g. ul a
- Universal, i.e. *
- Attribute, e.g. [type="text"]
- Pseudo-classes/-elements, e.g. a:hover
-Steve Souders
Browsers read selectors right-to-left!
Select ALL a tags, then check which ones are under #foo and return those
#foo a {...}
The right-most expression is called the 'key'. The key will affect performance the most.
Don't overqualify selectors
If you have this:
<ul id='nav'>
<li><a href="#home">Home</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
Don't do this:
#nav li a {...}
If you can do this:
#nav a {...}
-Harry Roberts
To prevent reflows, specify the width and height of all images, either in the HTML
tag, or in CSS
Credits
- http://google-styleguide.googlecode.com/
- http://developer.yahoo.com/performance/rules.html
- http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/
- http://www.slideshare.net/nzakas/writing-efficient-javascript
- http://csswizardry.com/2011/09/writing-efficient-css-selectors/
- http://stevesouders.com/
Rouben Meschian
rmeschian@gmail.com