Performing in the Browser


Jordi Boggiano   @seldaek

http://nelm.io/jordi

The Problem

Performance is money

Google Study

Experiments demonstrate that increasing web search latency 100 to 400 ms reduces the daily number of searches per user by 0.2% to 0.6%.

The browser is where it happens

Performance golden rule

Only 10-20% of the end user response time is spent downloading the HTML document. The other 80-90% are spent downloading all the components in the page.


Your super duper micro-framework that spits out Hello worlds at the speed of light does not matter.

Simple Solutions

Make fewer HTTP requests

Google Study

In 80% of pages, 10 or more resources are loaded from a single host.

The most popular sites could eliminate more than 8 HTTP requests per page if they combined all scripts [...] and stylesheets on the same host into one.

Make fewer HTTP requests

Merge assets (less CSS/JS)

Use CSS sprites (less images) and Data URIs (more on this later)

Minify JS/CSS

JS: Google Closure Compiler, YUI Compressor

CSS: tons of libs available for every language

Gzip

Google Study

The average web page takes up to 320 KB on the wire.
Only two-thirds of the compressible material on a page is actually compressed.

Gzip

Compress text, js, css, html

Don't touch images and other compressed files

CSS in <head>

JS right before </body>

Add the right headers

What you should have:

Cache-Control HTTP/1.1, relative, takes precedence

Expires HTTP/1.0, absolute time

Last-Modified needs a round-trip even for 304 Not Modified responses


What you most likely don't need:

ETag default config harmful to redundant setups, mostly useless when all of the above is implemented

Cache AJAX requests

They're nothing special

That was all fairly easy and quick

There is no excuse not to do it


Find more info in Pierre Spring's Speedy App slides

Going Further

Use HTML5

Shorter (and rememberable!) doctype

<!DOCTYPE html>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

Minify markup with HTML5

HTML5 also made valid many "bad practices" that have been working in all browsers for ages, but were considered invalid in HTML4

Minify markup with HTML5

<meta charset="utf-8">

<meta http-equiv="content-type" content="text/html; charset=utf-8">

Minify markup with HTML5

<style>

<style type="text/css">

<script>

<script type="text/javascript">

Reduce image size, lossless

cli: pngcrush, online: smushit.com

Use data URIs

.foo {
    url(data:image/png;base64,R0lGOD...)
}
            
<img src="data:image/png;base64,R0lGOD..." />
            

e.g. Google Image, minifying CSS

Supported in IE8 (32KB) and IE9 + all others

MHTML for IE<8, or just don't bother

Use data URIs

Going further: inline all CSS, JS & images for requests without sessions, then lazy load for subsequent requests

You can cache the full homepage with everything inlined and serve it instantly, great experience for first time visitors

Deferred and Asynchronous scripts

document.write('fail');
            
<script src="blocking.js" />
<script src="deferred.js" defer />
<script src="async.js" async defer />
            

defer: HTML4/IE

async: HTML5

Deferred and Asynchronous scripts

var ga = document.createElement('script');
ga.src = 'http://www.google-analytics.com/ga.js';
ga.async = true;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
            

Manage reflows

Most changes to the DOM trigger reflows/repaints:

Adding/Removing nodes

Changing styles, classes, ..

(Sometimes) Retrieving offsetWidth, getComputedStyle(), etc.


Check it out with Firebug Paint Events

Manage reflows

Use document fragments

var elem, i,
    foo = document.getElementsById("foo"),
    texts = ["a", "b", "c"];

for (i = 0; i < texts.length; i++) {
    elem = document.createElement('p');
    p.innerHTML = texts[i];
    foo.appendChild(elem);
}
            

Manage reflows

Use document fragments

var elem, i,
    foo = document.getElementsById("foo"),
    texts = ["a", "b", "c"],
    fragment = document.createDocumentFragment();

for (i = 0; i < texts.length; i++) {
    elem = document.createElement('p');
    p.innerHTML = texts[i];
    fragment.appendChild(elem)
}
foo.appendChild(fragment);
            

Manage reflows

Add/remove classes (atomic operation) instead of changing multiple css styles

Manage reflows

Animate items out of the page flow by using absolute or fixed positioning.

NavigationTiming API

Chrome6+, IE9 for now

Access via window.performance.timing and window.performance.navigation

Spec at http://test.w3.org/webperf/specs/NavigationTiming/

NavigationTiming API

NavigationTiming API

Quick demo

Now go and do it! (please?)

Most of this is very easy to set up with decent infrastructure, and can cut load times by half easily.

References & Links

Thank you.

Questions?

Slides up at slides.seld.be

Feedback please on
http://joind.in/2824