Shifting Gears
-
Upload
christian-heilmann -
Category
Technology
-
view
9.650 -
download
2
description
Transcript of Shifting Gears
Shifting your site into the next gear
Christian Heilmann | http://wait-till-i.com | http://twitter.com/codepo8
GeekMeet, Stockholm, Sweden, December 2008
htt
p:/
/ww
w.f
lick
r.co
m/p
ho
tos/
fab
iove
nn
i/91
7803
34/
Hello there...
I’m Chris.
It is great to be in Sweden...
...especially when you live in England...
Ok, I originally meant not to make any naughty jokes.
But then I saw the Adwords Robert seems to have bought
for GeekMeet.
... enough of this, let’s get serious ...
The performance of your web product is immensely important
And there are several small tricks and ideas that can
increase the performance significantly.
There is a lot of research being done on the subject in
a lot of companies...
...and this information is available for free for you.
I’ll provide the links and names later...
...but for now let’s see what is slowing our sites down.
Things that slow you down
http://www.flickr.com/photos/pikerslanefarm/2428232674/
<script>
JavaScript is awesome.
Browsers think so, too.
Which means that every time they encounter a script node
they take a break.
<script> </script>
Rendering stops and the JavaScript parser takes over.
If there is code inside the tag, this code is analyzed and
executed before the browser goes back to rendering.
If there is a src attribute, the file it points to gets loaded,
parsed and executed.
This can take time as the browser (with third party
files) needs to get the right domain information, contact the other server, get the file
and then move on.
This gets worse the more script nodes you use.
The first question is then where to put scripts?
The gospel according to Heilmann, 2006:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html lang="se-se(bork bork)"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script type="text/javascript" src="myscripts.js"></script></head><body><!-- lots of HTML here --></body></html>
This has some benefits:
You can be sure your JavaScript is loaded before the document is displayed.
You make it easier for other developers to debug – they know where the scripts are.
On the other hand...
You delay the display of the page until all the scripts are
loaded and executed.
You need to delay the access to any HTML to change or
enhance until it is available – onload, onavailable, oncontentloaded.
This is hacky!
The gospel according to performance specialists
2007/2008:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html lang="se-se(bork bork)"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title></head><body><!-- lots of HTML here --> <script type="text/javascript" src="myscripts.js"></script></body></html>
The benefits are:
Your scripts don’t delay the rendering of the HTML.
HTML is available for enhancing.
The problems:
You don’t put scripts where people normally expect
them.
The HTML is already available for people to interact with before you can apply your
enhancement voodoo.
The recipe for performance and usability success?
Of course you need testing on your apps and sites to find
your perfect solution...
But here are some ideas:
How about a mix of both?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html lang="se-se(bork bork)"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script type="text/javascript" src="main.js"></script></head><body><!-- lots of HTML here --> <script type="text/javascript" src="secondary.js"></script></body></html>
You can even execute delayed without hacks.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html lang="se-se(bork bork)"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script type="text/javascript" src="main.js"></script></head><body><!-- lots of HTML here --> <script type="text/javascript">doStuff()</script> <script type="text/javascript" src="secondary.js"></script></body></html>
The first script can set a class called js on the body of the
document.
Which allows you to define two styles, one for the non-
scripting version and one for the dynamic one.
In the dynamic one you hide the problematic elements
that could be activated prematurely.
Once the functionality has been added, add another
class that undoes this.
.js #buttons{ position:absolute; top:0; left:-6000px;}.jsloaded #buttons{ position:relative; top:0; left:0;}
CSS parsers are very fast!
What about the multiple scripts issue?
Chunking your JavaScript into several includes all doing one job at a time is a great idea to
keep your solutions maintainable.
<script type="text/javascript" src="config.js"></script><script type="text/javascript" src="base.js"></script><script type="text/javascript" src="effects.js"></script><script type="text/javascript" src="validation.js"></script><script type="text/javascript" src="widgets.js"></script>
This does not mean though that you need to add all of
them as single includes.
You can easily write a backend script that does that
for you:
<script type="text/javascript" src="/pack/config/base/effects/validation/widgets"></script>
Fun things to do in this script:
Run through JSLint.
Minify.
Replace all strings with an array lookup to stop IE from creating a string object for
each string.
Instead of doing this every time the page is loaded, you
can make it part of a build process.
And don’t forget to cache the result!
Get a script that does most of that from Ed Eliot:
http://www.ejeliot.com/blog/73
The other option is to be lazy.
Lazy loading is a concept to load dependencies only when
and if they are needed.
Your base.js could test for all the things that should
work...
...and if they do, create script nodes dynamically to load the other, chunkier parts.
This is a pretty nice idea as it only loads things when they
are needed...
...thus saving server traffic and diminishing loading time.
However, there are problems.
Asynchronous loading means you never know in which
order the loaded components come back to you...
You can work around that by creating callbacks, as
explained on 24ways last year:
http://24ways.org/2007/keeping-javascript-dependencies-at-bay
There are a lot more issues, for example that you might block document.write() of bad code ads in your page.
Steve Souders and Stoyan Stefanof have the whole
scoop:http://stevesouders.com/tests/delayed-script-execution.php
http://yuiblog.com/blog/2008/07/22/non-blocking-scripts/
What other things slow you down?
<img>
Images are what made the web what it is now.
Sure, linking text was a revolution.
But being able to get images on demand and store them
was something that triggered the “collector” in everyone.
Yeah, Pr0n.
Anyways, too many images slow down your site
immensely.
The reasons are the same delays you experience with
external scripts...
...except images don’t stop the rendering.
However only a few get loaded at a time...
...as the number of parallel connections of browsers is limited (with good reason)
Which means you should cut down on the amount of
images.
The best trick there is to use CSS sprites.
And again, Ed Eliot and Stuart Colville come to the rescue!
http://spritegen.website-performance.org/
You use Spritegen by uploading a zip of images...
...and it generates the CSS and the sprite image for you!
It is also open source in case you want to host it yourself.
How good are you in optimizing images?
Probably not as good as you think you are.
A lot of bytes can be squeezed out of images...
...without changing their visual outcome.
Choosing the right format in the right version can be quite
a drag.
And it doesn’t help that tools put all kind of pointless data into images (edited with xyz,
version abc...).
The easy way out?
http://smushit.com
What else could be a problem?
How about the amount of images on the page?
You can work around loading all the images by – once
again – delaying the loading.
The easy way is to prepend the images with a dummy
and then replace this.
<img src=”dummy.gif#kitten.jpg” alt=”a nice kitten”><img src=”dummy.gif#puppy.jpg” alt=”a nice puppy”>
<script type="text/javascript">window.onload = function(){
var imgs = document.getElementsByTagName(‘img’);for(var i=0;imgs[i];i++){var src = imgs[i].src;imgs[i].src = src.replace(‘dummy.gif#’,’’);
}}</script>
The more complex but cleverer way is to wait until
the images are in the viewport.
http://developer.yahoo.com/yui/imageloader/
You can see this trick in action at shine.yahoo.com
and YouTube.
It’d be cool if browsers did that anyways – anyone
remember lowsrc?
What else is slowing us down?
<object>, err <embed> err...
Flash and other plugins have the same issues as <script>
has.
You interfere with the browsers’ normal rendering
and they wait until the confusion is over.
The other issue of course is that making embedding work
and validate is a pain.
The solution for this is progressively enhancing
Flash embedding.
As you embed with JavaScript you can test for the correct
Flash support.
And you can delay the embedding by for example enhancing an image when
the user clicks on it.
SUMMARY TIME!
In general there are two things to do:
Collate and Delay :)
The tips and tools:
★ http://developer.yahoo.com/performance/★ http://www.stevesouders.com/★ http://website-performance.org/
★ YSlow: http://developer.yahoo.com/yslow/ ★ Hammerhead: http://stevesouders.com/hammerhead/
Christian Heilmann
http://scriptingenabled.org | http://wait-till-i.com
twitter/flickr: codepo8
THANSK!Svenska?