Shifting Gears


Published on

My first talk at geekmeet Sweden, talking about basics of web site performance.

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Shifting Gears

  1. Shifting your site into the next gear Christian Heilmann | | GeekMeet, Stockholm, Sweden, December 2008
  2. Hello there...
  3. I’m Chris.
  4. It is great to be in Sweden...
  5. ...especially when you live in England...
  6. Ok, I originally meant not to make any naughty jokes.
  7. But then I saw the Adwords Robert seems to have bought for GeekMeet.
  8. ... enough of this, let’s get serious ...
  9. The performance of your web product is immensely important
  10. And there are several small tricks and ideas that can increase the performance significantly.
  11. There is a lot of research being done on the subject in a lot of companies...
  12. ...and this information is available for free for you.
  13. I’ll provide the links and names later...
  14. ...but for now let’s see what is slowing our sites down.
  15. Things that slow you down
  16. <script>
  17. JavaScript is awesome.
  18. Browsers think so, too.
  19. Which means that every time they encounter a script node they take a break. <script> </script>
  20. Rendering stops and the JavaScript parser takes over.
  21. If there is code inside the tag, this code is analyzed and executed before the browser goes back to rendering.
  22. If there is a src attribute, the file it points to gets loaded, parsed and executed.
  23. 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.
  24. This gets worse the more script nodes you use.
  25. The first question is then where to put scripts?
  26. The gospel according to Heilmann, 2006:
  27. <!DOCTYPE HTML PUBLIC quot;-//W3C//DTD HTML 4.01//ENquot; quot;;> <html lang=quot;se-se(bork bork)quot;> <head> <meta http-equiv=quot;Content-Typequot; content=quot;text/ html; charset=utf-8quot; /> <title></title> <script type=quot;text/javascriptquot; src=quot;myscripts.jsquot;></script> </head> <body> <!-- lots of HTML here --> </body> </html>
  28. This has some benefits:
  29. You can be sure your JavaScript is loaded before the document is displayed.
  30. You make it easier for other developers to debug – they know where the scripts are.
  31. On the other hand...
  32. You delay the display of the page until all the scripts are loaded and executed.
  33. You need to delay the access to any HTML to change or enhance until it is available – onload, onavailable, oncontentloaded.
  34. This is hacky!
  35. The gospel according to performance specialists 2007/2008:
  36. <!DOCTYPE HTML PUBLIC quot;-//W3C//DTD HTML 4.01//ENquot; quot;;> <html lang=quot;se-se(bork bork)quot;> <head> <meta http-equiv=quot;Content-Typequot; content=quot;text/ html; charset=utf-8quot; /> <title></title> </head> <body> <!-- lots of HTML here --> <script type=quot;text/javascriptquot; src=quot;myscripts.jsquot;></script> </body> </html>
  37. The benefits are:
  38. Your scripts don’t delay the rendering of the HTML.
  39. HTML is available for enhancing.
  40. The problems:
  41. You don’t put scripts where people normally expect them.
  42. The HTML is already available for people to interact with before you can apply your enhancement voodoo.
  43. The recipe for performance and usability success?
  44. Of course you need testing on your apps and sites to find your perfect solution...
  45. But here are some ideas:
  46. How about a mix of both?
  47. <!DOCTYPE HTML PUBLIC quot;-//W3C//DTD HTML 4.01//ENquot; quot;;> <html lang=quot;se-se(bork bork)quot;> <head> <meta http-equiv=quot;Content-Typequot; content=quot;text/html; charset=utf-8quot; /> <title></title> <script type=quot;text/javascriptquot; src=quot;main.jsquot;></ script> </head> <body> <!-- lots of HTML here --> <script type=quot;text/javascriptquot; src=quot;secondary.jsquot;></ script> </body> </html>
  48. You can even execute delayed without hacks.
  49. <!DOCTYPE HTML PUBLIC quot;-//W3C//DTD HTML 4.01//ENquot; quot;;> <html lang=quot;se-se(bork bork)quot;> <head> <meta http-equiv=quot;Content-Typequot; content=quot;text/html; charset=utf-8quot; /> <title></title> <script type=quot;text/javascriptquot; src=quot;main.jsquot;></ script> </head> <body> <!-- lots of HTML here --> <script type=quot;text/javascriptquot;>doStuff()</script> <script type=quot;text/javascriptquot; src=quot;secondary.jsquot;></ script> </body> </html>
  50. The first script can set a class called js on the body of the document.
  51. Which allows you to define two styles, one for the non- scripting version and one for the dynamic one.
  52. In the dynamic one you hide the problematic elements that could be activated prematurely.
  53. Once the functionality has been added, add another class that undoes this.
  54. .js #buttons{ position:absolute; top:0; left:-6000px; } .jsloaded #buttons{ position:relative; top:0; left:0; }
  55. CSS parsers are very fast!
  56. What about the multiple scripts issue?
  57. Chunking your JavaScript into several includes all doing one job at a time is a great idea to keep your solutions maintainable.
  58. <script type=quot;text/javascriptquot; src=quot;config.jsquot;> </script> <script type=quot;text/javascriptquot; src=quot;base.jsquot;> </script> <script type=quot;text/javascriptquot; src=quot;effects.jsquot;> </script> <script type=quot;text/javascriptquot; src=quot;validation.jsquot;> </script> <script type=quot;text/javascriptquot; src=quot;widgets.jsquot;> </script>
  59. This does not mean though that you need to add all of them as single includes.
  60. You can easily write a backend script that does that for you:
  61. <script type=quot;text/javascriptquot; src=quot;/pack/config/base/ effects/validation/widgetsquot;> </script>
  62. Fun things to do in this script:
  63. Run through JSLint.
  64. Minify.
  65. Replace all strings with an array lookup to stop IE from creating a string object for each string.
  66. Instead of doing this every time the page is loaded, you can make it part of a build process.
  67. And don’t forget to cache the result!
  68. Get a script that does most of that from Ed Eliot:
  69. The other option is to be lazy.
  70. Lazy loading is a concept to load dependencies only when and if they are needed.
  71. Your base.js could test for all the things that should work...
  72. ...and if they do, create script nodes dynamically to load the other, chunkier parts.
  73. This is a pretty nice idea as it only loads things when they are needed...
  74. ...thus saving server traffic and diminishing loading time.
  75. However, there are problems.
  76. Asynchronous loading means you never know in which order the loaded components come back to you...
  77. You can work around that by creating callbacks, as explained on 24ways last year: dependencies-at-bay
  78. There are a lot more issues, for example that you might block document.write() of bad code ads in your page.
  79. Steve Souders and Stoyan Stefanof have the whole scoop: delayed-script-execution.php non-blocking-scripts/
  80. What other things slow you down?
  81. <img>
  82. Images are what made the web what it is now.
  83. Sure, linking text was a revolution.
  84. But being able to get images on demand and store them was something that triggered the “collector” in everyone.
  85. Yeah, Pr0n.
  86. Anyways, too many images slow down your site immensely.
  87. The reasons are the same delays you experience with external scripts...
  88. ...except images don’t stop the rendering.
  89. However only a few get loaded at a time...
  90. the number of parallel connections of browsers is limited (with good reason)
  91. Which means you should cut down on the amount of images.
  92. The best trick there is to use CSS sprites.
  93. And again, Ed Eliot and Stuart Colville come to the rescue!
  94. You use Spritegen by uploading a zip of images...
  95. ...and it generates the CSS and the sprite image for you!
  96. It is also open source in case you want to host it yourself.
  97. How good are you in optimizing images?
  98. Probably not as good as you think you are.
  99. A lot of bytes can be squeezed out of images...
  100. ...without changing their visual outcome.
  101. Choosing the right format in the right version can be quite a drag.
  102. And it doesn’t help that tools put all kind of pointless data into images (edited with xyz, version abc...).
  103. The easy way out?
  105. What else could be a problem?
  106. How about the amount of images on the page?
  107. You can work around loading all the images by – once again – delaying the loading.
  108. The easy way is to prepend the images with a dummy and then replace this.
  109. <img src=”dummy.gif#kitten.jpg” alt=”a nice kitten”> <img src=”dummy.gif#puppy.jpg” alt=”a nice puppy”> <script type=quot;text/javascriptquot;> 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>
  110. The more complex but cleverer way is to wait until the images are in the viewport.
  111. You can see this trick in action at and YouTube.
  112. It’d be cool if browsers did that anyways – anyone remember lowsrc?
  113. What else is slowing us down?
  114. <object>, err <embed> err...
  115. Flash and other plugins have the same issues as <script> has.
  116. You interfere with the browsers’ normal rendering and they wait until the confusion is over.
  117. The other issue of course is that making embedding work and validate is a pain.
  118. The solution for this is progressively enhancing Flash embedding.
  120. As you embed with JavaScript you can test for the correct Flash support.
  121. And you can delay the embedding by for example enhancing an image when the user clicks on it.
  123. In general there are two things to do:
  124. Collate and Delay :)
  125. The tips and tools: ★ ★ ★ ★ YSlow: ★ Hammerhead:
  126. THANSK! Svenska? Christian Heilmann | twitter/flickr: codepo8