today's class morning: afternoon: how we got here HTTP overview

Slides:



Advertisements
Similar presentations
High Performance Web Sites 14 rules for faster pages
Advertisements

Optimizing Websites with YSlow Tom Lianza Co-Founder Wishlisting.com Tom Lianza Co-Founder Wishlisting.com.
Building Fast 3rd-Party Webapps O'Reilly Velocity Web Performance and Operations Conference 24 June Lessons.
Introduction to Web Design Lecture number:. Todays Aim: Introduction to Web-designing and how its done. Modelling websites in HTML.
CS193H: High Performance Web Sites Lecture 9: Rule 5 – Put Stylesheets at the Top Steve Souders Google
CS193H: High Performance Web Sites Lecture 7: Add an Expires Header Steve Souders Google
Steve Souders Even Faster Themes Disclaimer: This content does not necessarily reflect.
High Performance Web Sites Essential Knowledge for Frontend Engineers
Steve Souders Even Faster Web Sites Disclaimer: This content does not necessarily.
Steve Souders Even Faster Web Sites best practices for faster pages Disclaimer: This.
Steve Souders Even Faster Web Sites (inside ma.tt) best practices for faster pages.
CS193H: High Performance Web Sites Lecture 16: Rule 13 – Configure ETags Steve Souders Google
CS193H: High Performance Web Sites Lecture 4: Class Projects Steve Souders Google
CS193H: High Performance Web Sites Lecture 13: Rule 10 – Minify JavaScript Steve Souders Google
Steve Souders Even Faster Web Sites Disclaimer: This content does not necessarily.
CS193H: High Performance Web Sites Lecture 22: Vol 2 – Optimize Images, Use Iframes Sparingly, Flush the Document Early Steve Souders Google
Steve Souders Life's too short, write fast code part 1 Disclaimer: This content does.
Steve Souders Even Faster Web Sites best practices for faster pages Disclaimer:
CS193H: High Performance Web Sites Lecture 1: Introduction Steve Souders Google
17% 83% iGoogle, primed cache the importance of frontend performance 9%91% iGoogle, empty cache.
CS193H: High Performance Web Sites Lecture 17: Rule 14 – Make Ajax Cacheable Steve Souders Google
CS193H: High Performance Web Sites Lecture 8: Rule 4 – Gzip Components
CS193H: High Performance Web Sites Lecture 21: Vol 2 – Split Dominant Domains Steve Souders Google
CS193H: High Performance Web Sites Lecture 14: Rule 11 – Avoid Redirects Steve Souders Google
High Performance Web Sites Essential Knowledge for Frontend Engineers
Exceptional Performance Evolution at Yahoo! Steve Souders Chief Performance Yahoo!
CS193H: High Performance Web Sites Lecture 3: HTTP and the Web 100 Performance Profile Steve Souders Google
CS193H: High Performance Web Sites Lecture 6: Use a CDN Steve Souders Google
Steve Souders Even Faster Web Sites best practices for faster pages Disclaimer: This content does not necessarily.
Steve Souders Life's too short, write fast code part 1 Disclaimer: This content does.
CS193H: High Performance Web Sites Lecture 20: Vol 2 – Don't Scatter Inline Scripts Steve Souders Google
Steve Souders Even Faster Web Sites best practices for faster pages Disclaimer: This content does not necessarily.
CS193H: High Performance Web Sites Lecture 5: Make Fewer HTTP Requests Steve Souders Google
CS193H: High Performance Web Sites Lecture 12: Rule 8 – Make JavaScript and CSS External Steve Souders Google
CS193H: High Performance Web Sites Lecture 19: Vol 2 – Load Scripts Without Blocking Steve Souders Google
CS193H: High Performance Web Sites Lecture 10: Rule 6 – Put Scripts at the Bottom Steve Souders Google
CS193H: High Performance Web Sites Lecture 2: The Importance of Frontend Performance Steve Souders Google
CS193H: High Performance Web Sites Lecture 11: Rule 7 – Avoid CSS Expressions Rule 9 – Reduce DNS Lookups Steve Souders Google
CS193H: High Performance Web Sites Lecture 18: Vol 2 – Split the Initial Payload Steve Souders Google
Web Performance Meetup 1 Web Performance 101 Jeremy
Web Performance Meetup 1 Web Performance Toolbelt Jeremy
Copyright © 2003 Pearson Education, Inc. Slide 3-1 Created by Cheryl M. Hughes The Web Wizards Guide to XML by Cheryl M. Hughes.
Chapter 7 Constructors and Other Tools. Copyright © 2006 Pearson Addison-Wesley. All rights reserved. 7-2 Learning Objectives Constructors Definitions.
Copenhagen, 6 December 2004 Modern CSS Principles Miruna Bădescu Finsiel Romania.
XP New Perspectives on Microsoft Office Word 2003 Tutorial 7 1 Microsoft Office Word 2003 Tutorial 7 – Collaborating With Others and Creating Web Pages.
September Public Library Web Managers Workshop 2000 Cascading Style Sheets Manjula Patel UKOLN University of Bath Bath, BA2 7AY UKOLN is funded.
Slice and Dice: From PSD Image to XHTML+CSS Svetlin Nakov Telerik Corporation
Stevesouders.com/docs/velocity-wpo pptx Disclaimer: This content does not necessarily reflect the opinions of my employer.
The basics for simulations
User Friendly Price Book Maintenance A Family of Enhancements For iSeries 400 DMAS from Copyright I/O International, 2006, 2007, 2008, 2010 Skip Intro.
INTRODUCTION Lesson 1 – Microsoft Word Word Basics
CS193H: High Performance Web Sites Lecture 24: Vol 2 – CSS Descendant Selectors, Forced Compression Steve Souders Google
 Copyright I/O International, 2013 Visit us at: A Feature Within from Item Class User Friendly Maintenance  Copyright.
HIGH LEVEL OVERVIEW: CSS CSS SYNTAX CONSISTS OF A SET OF RULES THAT HAVE 3 PARTS: A SELECTOR, A PROPERTY, AND A VALUE. IT’S NOT NECESSARY TO REMEMBER THIS.
CIS67 Foundations for Creating Web Pages Professor Al Fichera Rev. September 22, 2010—All HTML code brought to XHTML standards. Reference for CIS127 and.
Chapter 11 Creating Framed Layouts Principles of Web Design, 4 th Edition.
CHAPTER 15 WEBPAGE OPTIMIZATION. LEARNING OBJECTIVES How to test your web-page performance How browser and server interactions impact performance What.
PHP Meetup - SEO 2/12/2009. Where to Focus? Ensuring the findability of content Ensuring content is well understood by search engines Maximizing the importance.
Unit 3 Day 4 FOCS – Web Design. No Journal Entry.
Copyright © Terry Felke-Morris WEB DEVELOPMENT & DESIGN FOUNDATIONS WITH HTML5 Chapter 6 Key Concepts 1 Copyright © Terry Felke-Morris.
Today CSS HTML A project.
Copyright © Terry Felke-Morris WEB DEVELOPMENT & DESIGN FOUNDATIONS WITH HTML5 Chapter 6 Key Concepts 1 Copyright © Terry Felke-Morris.
High Performance Websites (Based on Steve Souder’s lecture) By Bhoomi Patel.
Mark Phillip markphillip.com 200s, 304s, Expires Headers, HTTP Compression, And You.
Performance, SEO, Accessibility Ivan Zhekov Telerik Corporation
CNIT 133 Interactive Web Pags – JavaScript and AJAX JavaScript Environment.
PERFORMANCE ENHANCEMENT IN ASP.NET By Hassan Tariq Session #1.
Enhance Your Page Load Speed And Improve Traffic.
Web Caching? Web Caching:.
CSCI-351 Data communication and Networks
Presentation transcript:

today's class morning: afternoon: how we got here HTTP overview High Performance Web Sites: Rules 1-6 break exercise: Web 100 stats High Performance Web Sites: Rules 7-14 afternoon: morning wrap-up Even Faster Web Sites: chapters 1-4 Even Faster Web Sites: chapters 5-8 exercise: web site performance analysis state of performance

logistics slides: install: ask questions! http://stevesouders.com/docs/oreilly-master-class.ppt install: Firebug - http://getfirebug.com/ YSlow - http://developer.yahoo.com/yslow/ Hammerhead – http://stevesouders.com/hammerhead/ ask questions! candidate questions appear after each section – if you can't answer these, ask

how we got here HTTP overview HPWS Rules 1-6 break web 100 HPWS 7-14

the importance of frontend performance 9% 91% 17% 83% iGoogle, primed cache Data source: Steve Souders Tested on IE6 on Comcast cable modem (~5 mbps) medium powered PC, April 2008. iGoogle, empty cache

time spent on the frontend Empty Cache Primed Cache www.aol.com 97% www.ebay.com 95% 81% www.facebook.com www.google.com/search 47% 0% search.live.com/results 67% www.msn.com 98% 94% www.myspace.com en.wikipedia.org/wiki 91% www.yahoo.com 96% www.youtube.com

14 Rules Make fewer HTTP requests Use a CDN Add an Expires header Gzip components Put stylesheets at the top Put scripts at the bottom Avoid CSS expressions Make JS and CSS external Reduce DNS lookups Minify JS Avoid redirects Remove duplicate scripts Configure ETags Make AJAX cacheable 14 Rules photo courtesy of Vicki & Chuck Rogers: http://www.flickr.com/photos/two-wrongs/205467442/

evangelism Conferences Conferences Companies Web 2.0 Expo The Ajax Experience OSCON Google/IO SXSW Companies Yahoo! Amazon Zillow Microsoft Conferences WordCamp Future of Web Apps Widget Summit Velocity Rich Web Experience Apple Netflix Twitter LinkedIn Google Facebook CBS Interactive

September 2007

June 2009

how we got here HTTP overview HPWS Rules 1-6 break web 100 HPWS 7-14

basic HTTP Request request headers status code Response GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 request headers status code Response HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 6230 function d(s) {... response headers response body

compression GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 Accept-Encoding: gzip,deflate GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 6230 function d(s) {... HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 2066 Content-Encoding: gzip XmoÛHþ\ÿFÖvã*wØoq... Might want to set Vary:Accept-Encoding and Cache-Control:private

Expires GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 Accept-Encoding: gzip,deflate HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 2066 Content-Encoding: gzip XmoÛHþ\ÿFÖvã*wØoq... HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 2066 Content-Encoding: gzip Expires: Fri, 26 Sep 2008 22:00:00 GMT XmoÛHþ\ÿFÖvã*wØoq... Expiration date determines freshness. Can also use Cache-Control: max-age

Conditional GET (IMS) sometime after 3pm PT 9/24/08: GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 Accept-Encoding: gzip,deflate If-Modified-Since: Mon, 22 Sep 2008 21:14:35 GMT GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 Accept-Encoding: gzip,deflate HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 2066 Content-Encoding: gzip Expires: Fri, 26 Sep 2008 22:00:00 GMT XmoÛHþ\ÿFÖvã*wØoq... HTTP/1.1 304 Not Modified IMS determines validity. IMS is used when Reload is pressed. ETag and If-None-Match also determine validity.

questions What are the two key questions when reading resources from the cache? What is the request header and response header used to negotiate compression? What are the two response headers you can use to set an expiration date? What response header provides the file timestamp of the requested resource? What are the two request headers used to determine resource validity?

empty vs. primed cache empty: primed (same session): 30 HTTP requests 194Kb xferred 3.382 seconds 0.0 0.515 0.920 3.382 primed (same session): 1 HTTP request, 15 cache reads 8Kb xferred 0.515 seconds cache reads primed (diff session): 4 HTTP requests, 28 cache reads 13Kb xferred 0.920 seconds

memory cache Why is "primed cache same session" different from "primed cache different session"? Browsers store resources in memory so they don't need to read them from disk. What determines whether a resource is held in memory cache? I don't know. That'd be a good research project.

disk cache Two considerations with disk cache Is the resource fresh (vs. expired)? If it's expired, is it valid (vs. updated)? If a resource is fresh, no HTTP request is made – it's just read from disk. If a resource is expired, a Conditional GET request is made. If the resource is valid, it's read from disk and the Conditional GET response is empty. If the resource has been updated, the Conditional GET response contains the updated version.

packet sniffers measure HTTP requests HTTPWatch Firebug net panel http://www.httpwatch.com/ IE and Firefox, Windows only Firebug net panel less accurate timings (includes blocking time) others: AOL Pagetest (web-based), Fiddler (Windows), Wireshark (low-level), IBM Page Detailer (Windows)

Firebug Joe Hewitt, January 2006 Firebug Working Group, Mozilla came onboard kit and caboodle: inspect HTML CSS explanation and modification DOM inspector network monitor JavaScript console, log, debugger and profiler add-on to Firefox Firebug Lite – bookmarklet for IE, Safari, Opera, etc. Open Source (free) http://getfirebug.com/

YSlow

YSlow Steve Souders, July 2007 web performance analysis tool add-on to Firebug (extension to an extension) Open Source (free), not open repository http://developer.yahoo.com/yslow/

questions What's the white space in the HTTP profiles? Why is the HTML document typically not cached? Why are packet sniffers not good for measuring page load time?

how we got here HTTP overview HPWS Rules 1-6 break web 100 HPWS 7-14

the importance of frontend performance 9% 91% 17% 83% iGoogle, primed cache Data source: Steve Souders Tested on IE6 on Comcast cable modem (~5 mbps) medium powered PC, April 2008. iGoogle, empty cache

definitions Backend Frontend Time from when the user makes the request to when the last byte of the HTML document arrives. Includes the time for the initial request to go up, the web server to stitch together the HTML, and for the response to come back. Frontend Shorthand for everything after the HTML document arrives. In reality, includes backend time (primarily reading static files) and network time, as well as true frontend activities such as parsing HTML, CSS, and JS, and executing JS.

time spent on the frontend Empty Cache Primed Cache www.aol.com 97% www.ebay.com 95% 81% www.facebook.com www.google.com/search 47% 0% search.live.com/results 67% www.msn.com 98% 94% www.myspace.com en.wikipedia.org/wiki 91% www.yahoo.com 96% www.youtube.com

The Performance Golden Rule 80-90% of the end-user response time is spent on the frontend. Start there. greater potential for improvement simpler If you could cut performance in half, FE changes would be 40-45%, while BE would be only 5-10%. BE changes are typically more complex: rearchitecture, optimize code, add/modify hw, distribute databases, etc. FE is simpler: change web server config, place scripts and stylesheets differently in the page, combine requests, etc. I’ve worked with dev teams to cut response times on 50 properties, often by 25% or more. And feedback from other companies is similar. Permission to use photo given by Technicolor: http://flickr.com/photos/technicolor/44988148/ proven to work

Rule 1: Make Fewer HTTP Requests 80-90% of load time is the frontend the frontend time is dominated by HTTP HTTP requests growth since 2003: 25 to 50* each HTTP request has overhead – even with persistent connections reducing HTTP requests has the biggest impact bigger benefit for users with higher latency parallelization reduces the need for this * http://www.websiteoptimization.com/speed/tweak/average-web-page/

Rule 1: Make Fewer HTTP Requests But... is it possible to reduce HTTP requests without reducing richness? Yes: combine JS, CSS image maps CSS sprites inline images

combine JS and CSS not combining scripts with stylesheets multiple scripts => one script multiple stylesheets => one stylesheet apache module: http://code.google.com/p/modconcat/ YUI Combo Handler http://yuiblog.com/blog/2008/07/16/combohandler/ http://stevesouders.com/examples/combo.php

image maps old school, CSS sprites is preferred <img usemap="#map1" border=0 src="/images/imagemap.gif"> <map name="map1"> <area shape="rect" coords="0,0,31,31" href="home.html"> <area shape="rect" coords="36,0,66,31" href="gifts.html"> <area shape="rect" coords="71,0,101,31" href="cart.html"> <area shape="rect" coords="106,0,136,31" href="settings.html"> <area shape="rect" coords="141,0,171,31" href="help.html"> </map> old school, CSS sprites is preferred image maps still useful when x,y coordinates are useful, for example, in maps http://stevesouders.com/examples/imagemap.php

CSS sprites multiple CSS background images => one image <div style="background-image: url('a_lot_of_sprites.gif'); background-position: -260px -90px; width: 26px; height: 24px;"> </div> overall size reduced generator: http://spritegen.website-performance.org/ http://stevesouders.com/examples/sprites.php

inline images (data: URLs) embed the content of an HTTP response in place of a URL <IMG ALT="Red Star" SRC="data:image/gif;base64,R0lGODl...wAIlEEADs="> if embedded in HTML document, probably not cached => embed in stylesheet instead base64 encoding increases total size works in IE8 (not IE7 and earlier) http://stevesouders.com/examples/inline-images.php

data: URLs not just for images Hammerhead: <frame src="data:text/html,%3Chtml%3E%3Cbody%20style%3D%22background..."></frame>

Rule 2: Use a CDN Content Delivery Network geographically distributed servers => closer to your users also: backups, storage, caching, absorb spikes Akamai, Mirror Image, Limelight, Savvis new: Amazon S3, Panther Express (more affordable) dynamic content: 1 HTTP request static content: all the rest distribute your static content before distributing your dynamic content

CDN – reverse proxy CDN Origin Server(s) Edge Servers name server 198.87.82.45 ISP's DNS Resolver 198.87.82.45 198.87.82.45 User Developer CDN Origin Server(s) Edge Servers

CDN usage CDN www.aol.com Akamai www.ebay.com www.facebook.com www.google.com/search search.live.com/results www.msn.com www.myspace.com en.wikipedia.org/wiki www.yahoo.com www.youtube.com

questions What's the most important requirement for a CDN? How can you find out which CDN a company uses? What plays the key role in sending users to the appropriate edge server?

Rule 3: Add an Expires Header GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 Accept-Encoding: gzip,deflate HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 2066 Content-Encoding: gzip Expires: Mon, 12 Oct 2009 14:57:34 GMT Cache-Control: max-age=31536000 XmoÛHþ\ÿFÖvã*wØoq... Expiration date determines freshness. Can also use Cache-Control: max-age

Expires vs. max-age Expires works in HTTP/1.0, max-age in HTTP/1.1 Expires is an absolute date: 12 Oct 2009 14:57:34 GMT max-age is # of seconds until expiration: 31536000 Expires relies on clock synchronization between client and server for short expirations max-age takes precedence over Expires

sending Expires (Apache) mod_expires <FilesMatch "\.(gif|jpg|js|css)$"> ExpiresDefault "access plus 1 year" </FilesMatch> sends both Expires and max-age: Expires: Mon, 12 Oct 2009 14:57:34 GMT Cache-Control: max-age=315360000

Expires in the wild – 2007 Images Scripts Stylesheets % with Expires Median Age amazon.com 0/62 0/3 0/1 0% 114 days aol.com 23/43 6/18 1/1 48% 217 days cnn.com 0/138 2/11 0/2 1% 227 days ebay.com 16/20 0/7 55% 140 days froogle.google.com 1/23 4% 454 days msn.com 32/35 3/9 80% 34 days myspace.com 0/18 1 day wikipedia.org 6/8 2/3 75% yahoo.com 23/23 4/4 100% na youtube.com 0/32 26 days average 10/40 (25%) 2/5 (38%) 0.5/2 (27%) 12/46 (26%) March 2007

Expires in the wild – 2008 Images Scripts Stylesheets % with Expires Median Age aol.com 26/35 13/20 1/1 71% 189 days ebay.com 48/48 6/7 2/2 98% 1 day facebook.com 93/97 20/22 20/20 96% 121 days google.com/search 0/1 0/0 50% search.live.com/results 6/6 4/4 100% na msn.com 45/45 3/3 myspace.com 21/21 7/7 en.wikipedia.org/wiki 7/32 5/5 9/9 46% 310 days yahoo.com 23/23 youtube.com 8/27 34% unk average 28/34 (83%) 6/7 (85%) 5/5 (100%) 38/45 (85%) October 2008

revving filenames (really, this is independent of Expires headers) once you make a resource public, you can never change it => aggressive proxies prevent 100% of users from getting the update best solution: change the filename date: trough_062308.gif version #: onload_1.6.1.js checksum: 1076572916-dom.common.js don't use querystring: wikibits.js?179 won't be cached by some proxies

questions What's are some differences between Expires and max-age? What types of resources should an Expires or a Cache-Control header be used with? Once a resource is cached with a far future expiration date, how can you push updates and ensure users get the new version?

Rule 4: Gzip Components typically reduces size by 70% GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 Accept-Encoding: gzip,deflate GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 6230 function d(s) {... HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 2066 Content-Encoding: gzip XmoÛHþ\ÿFÖvã*wØoq... typically reduces size by 70% (6230-2066)/6230 = 67%

gzip vs. deflate gzip (default settings) compresses more Gzip Deflate Size Savings Script 3.3K 1.1K 67% 66% 39.7K 14.5K 64% 16.6K 58% Stylesheet 1.0K 0.4K 56% 0.5K 52% 14.1K 3.7K 73% 4.7K gzip (default settings) compresses more

pros and cons Pro: smaller transfer size Con: CPU cycles – on client and server Don't compress resources < 1K

gzip configuration Apache 1.3: mod_gzip Apache 2.x: mod_deflate mod_gzip_item_include file \.html$ mod_gzip_item_include mime ^text/html$ mod_gzip_item_include file \.js$ mod_gzip_item_include mime ^application/x-javascript$ mod_gzip_item_include file \.css$ mod_gzip_item_include mime ^text/css$ Apache 2.x: mod_deflate AddOutputFilterByType DEFLATE text/html text/css application/x-javascript control compression level: DeflateCompressionLevel http://httpd.apache.org/docs/2.0/mod/mod_deflate.html

gzip: not just for HTML gzip scripts, stylesheets, XML, JSON amazon.com x aol.com some cnn.com ebay.com froogle.google.com msn.com deflate myspace.com wikipedia.org yahoo.com youtube.com HTML Scripts Stylesheets aol.com x ebay.com some facebook.com google.com/search na search.live.com/results msn.com myspace.com en.wikipedia.org/wiki yahoo.com youtube.com Images and PDF files are already compressed. Gzipping them wastes CPU and can increase file sizes. gzip scripts, stylesheets, XML, JSON (not images, Flash, PDF) October 2008 March 2007

edge case: proxies Proxy Origin Server 1 GET main.js Accept-Encoding: gzip 2 GET main.js Accept-Encoding: gzip 5 main.js Content-Encoding: gzip 3 main.js Content-Encoding: gzip 6 GET main.js (no Accept-Encoding) 7 main.js Content-Encoding: gzip 4 main.js Content-Encoding: gzip proxies may serve gzipped content to browsers that don't support it, and vice versa

edge case: proxies w/ Vary Proxy Origin Server 1 GET main.js Accept-Encoding: gzip 2 GET main.js Accept-Encoding: gzip 7 GET main.js (no Accept-Encoding) 5 main.js Content-Encoding: gzip 3 main.js Content-Encoding: gzip Vary: Accept-Encoding 6 GET main.js (no Accept-Encoding) 8 main.js Vary: Accept-Encoding 10 main.js (no gzip) 4 main.js Content-Encoding: gzip [Accept-Encoding: gzip] 11 GET main.js Accept-Encoding: gzip 12 main.js Content-Encoding: gzip 9 main.js [Accept-Encoding: ] 13 GET main.js (no Accept-Encoding) add Vary: Accept-Encoding 14 main.js (no gzip)

edge case: bad browsers < 1% of browsers have problems with gzip IE 5.5: http://support.microsoft.com/default.aspx?scid=kb;en-us;Q313712 IE 6.0: http://support.microsoft.com/default.aspx?scid=kb;en-us;Q31249 Netscape 3.x, 4.x http://www.schroepl.net/projekte/mod_gzip/browser.htm User-Agent white list for gzip Apache 1.3: mod_gzip_item_include reqheader "User-Agent: MSIE [6-9]" mod_gzip_item_include reqheader "User-Agent: Mozilla/[5-9]" Apache 2.0: BrowserMatch ^MSIE [6-9] gzip BrowserMatch ^Mozilla/[5-9] gzip

edge case: bad browsers (cont'd) proxies could mix-up responses give cached response from useragent1 to useragent2 could add Vary: User-Agent so many possibilities, defeats proxy caching better to add Cache-Control: Private downside: disables all proxy caches is it a serious problem? hard to diagnose; problem getting smaller

edge case: ETags what happens when proxy makes Conditional GET requests? Last-Modified date for gzipped vs. ungzipped is different => If-Modified-Since works fine ETag is the same in Apache for gzipped & ungzipped => If-None-Match succeeds, proxy could give browser mismatched content remove Etags! (Rule 13) http://issues.apache.org/bugzilla/show_bug.cgi?id=39727

edge case: ETags present Proxy Origin Server 1 GET main.js Accept-Encoding: gzip 2 GET main.js Accept-Encoding: gzip 7 GET main.js If-None-Match: "de158-e58-c7ee4140" 5 main.js Content-Encoding: gzip 3 main.js Content-Encoding: gzip Cache-Control: max-age=0 ETag: "de158-e58-c7ee4140" 6 GET main.js (no Accept-Encoding) 8 304 Not Modified 9 main.js Content-Encoding: gzip 4 main.js Content-Encoding: gzip Cache-Control: max-age=0 ETag: "de158-e58-c7ee4140" proxy gives browser mismatched content

edge case: ETags removed Proxy Origin Server 1 GET main.js Accept-Encoding: gzip 2 GET main.js Accept-Encoding: gzip 7 GET main.js If-Modified-Since: Thu, 21 Aug 2008 23:53:57 GMT 5 main.js Content-Encoding: gzip 3 main.js Content-Encoding: gzip Cache-Control: max-age=0 Last-Modified: Thu, 21 Aug 2008 23:53:57 GMT 6 GET main.js (no Accept-Encoding) 8 main.js Cache-Control: max-age=0 Last-Modified: Fri, 22 Aug 2008 09:43:15 GMT 10 main.js (no gzip) 4 main.js Content-Encoding: gzip Cache-Control: max-age=0 Last-Modified: Thu, 21 Aug 2008 23:53:57 GMT 9 main.js Cache-Control: max-age=0 Last-Modified: Fri, 22 Aug 2008 09:43:15 GMT removing ETags avoids the problem

Vary: Accept-Encoding Cache-Control: private edge case fixes Vary: Accept-Encoding Cache-Control: private ETag aol.com x ebay.com x (IIS) facebook.com google.com/search search.live.com/results msn.com myspace.com x (Apa) en.wikipedia.org/wiki yahoo.com youtube.com some Images and PDF files are already compressed. Gzipping them wastes CPU and can increase file sizes. Vary: User-Agent – not used October 2008 March 2007

questions How much are file sizes typically reduced by using gzip compression? What types of resources (images, scripts, etc.) should not be compressed? For the resource types that should be compressed, should they always be compressed? How do you prevent proxies from serving gzipped resources to browsers that don't support gzip? How can ETags cause proxies to serve mismatched content to browsers?

Rule 5: Put Stylesheets at the Top progress indicators:* reassure the system is working convey how much time is left provide something to look at the web page is the progress indicator progressive rendering – draw content as soon as it's available stylesheets block progressive rendering in IE, and cause "flash" in Firefox David Hyatt talks about how browsers work: http://weblogs.mozillazine.org/hyatt/archives/2004_05.html#005496 *Jakob Nielson, http://www.useit.com/papers/responsetime.html

stylesheets in IE in IE, nothing in the page is drawn until all stylesheets are done downloading reasoning: parse all rules before drawing any element, avoids having to redraw when stylesheets are at the bottom, there is no progressive rendering => after a long delay the entire page blasts onto the screen http://stevesouders.com/examples/css-fouc.php

IE: fastest feels slowest... ...and slowest feels fastest stylesheet at bottom: content finishes downloading sooner, but rendering starts later => feels slower stylesheet at top: content finishes downloading later, but rendering starts sooner => feels faster true in IE 6, 7, 8

stylesheets in Firefox in Firefox, elements are drawn even if stylesheets aren't all downloaded reasoning: progressive rendering makes the page feel faster (most developers will follow the spec and put their stylesheets in HEAD?) when stylesheets are at the bottom and they change style of rendered elements, elements have to be redrawn => flash of unstyled content http://stevesouders.com/examples/css-fouc.php

FF2: stylesheets block stylesheets block downloads in Firefox 2 fixed in Firefox 3

IE 6,7 and mime filters mime filter plug-ins alter behavior for specific mime types in IE 6,7 mime filters can affect performance

resource.cgi formerly sleep.cgi http://stevesouders.com/bin/resource.cgi ?type=[gif|js|css|html|swf] &sleep=n – number of seconds &expires=[-1|0|1] – sets Expires header in the past (-1), future (1), or none (0) useful in exaggerating load times making it possible to observe browser behavior

questions What is progressive rendering? How do stylesheets affect progressive rendering in IE? in Firefox? Why do they take different approaches? What's the best way to avoid these problems?

Rule 6: Put Scripts at the Bottom HTTP spec recommends only two connections (parallel downloads) per hostname http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4 results in a stairstep pattern general rule: page load time increases for every two resources added

more connections newer browsers open more connections per hostname Chrome 6 Firefox 2 2 Firefox 3 IE 6,7 IE 8 Opera 8 Safari 4 domain sharding – split resources across multiple domains to increase parallelization previous example using two domains browser looks at name, not IP address

parallelization is an opportunity for improving load times

Rule 6: Put Scripts at the Bottom unfortunately, scripts block in two ways downloading resources below the script rendering elements below the script http://stevesouders.com/hpws/js-middle.php moving the scripts lower means less blocking

challenges document.write ads code dependencies scripts that perform document.write must be placed where the content is to be inserted alternative: set element.innerHTML ads ads typically are at the top of the page and include scripts alternative: use iframes or lazy-load ads code dependencies some JavaScript must occur higher in the page, and it depends on other scripts alternative: move scripts as low as possible, combine them

parallel script loading execute scripts in order, but download them in parallel with other resources available in IE8, Safari 4, Chrome 2 coming in Firefox 3.5 IE6&7 will be around for years, we have to keep them in mind, so… put scripts at the bottom

questions How many connections per hostname is suggested in the HTTP/1.1 spec? Do all browsers follow this recommendation? What's domain sharding? In what way do scripts block a web page? Give a situation where you can't just move a script to the bottom of the page. Which browsers support parallel script loading?

how we got here HTTP overview HPWS Rules 1-6 break web 100 HPWS 7-14

how we got here HTTP overview HPWS Rules 1-6 break web 100 HPWS 7-14

exercise: Web 100 stats pick two web sites http://spreadsheets.google.com/ccc?key=pFI0gp5Gg0kHISKLVMRP9cQ pick two web sites put your name in "reviewer name" column (each web site has two reviewers) use Hammerhead to measure total load time (columns B & C) use YSlow to measure the rest if you're the last one finished with a web site and your stats are very different, find the other reviewer and try to resolve

how we got here HTTP overview HPWS Rules 1-6 break web 100 HPWS 7-14

Rule 7: Avoid CSS Expressions used to set CSS properties dynamically in IE 5-7 fixes IE CSS 2.1 bugs and shortcomings, such as lack of support for min-width min-width: 600px; width: expression( document.body.clientWidth < 600 ? “600px” : “auto” ); problem: expressions execute 1000s of times mouse move, key press, resize, scroll, etc. http://stevesouders.com/hpws/expression-counter.php (IE only!) expression's JavaScript can slow down pages

alternatives to expressions expressions are evaluated all the time (mouse move, etc.), this is what makes them easy but slow alternatives are more work, but reduce the amount of JavaScript code executed alternatives: one-time expressions event handlers

one-time expressions if an expression only needs to be calculated once, it can overwrite itself with the value <style> #maindiv { min-width: 600px; width: expression(setW(this));} </style> <script type="text/javascript"> function setW(elem) { elem.style.runtimeStyle.width = ( document.body.clientWidth < 600 ? "600px" : "auto" ); } </script> doesn't handle window resizing overwrite the expression

event handlers tie the code to the specific event(s) of interest <style> #maindiv { min-width: 600px; width: expression(setW(this));} </style> <script type="text/javascript"> function setW() { elem=document.getElementById('maindiv'); elem.style.runtimeStyle.width = ( document.body.clientWidth < 600 ? "600px" : "auto" ); } window.onresize = setW; </script>

Expressions in IE8 expressions are no longer supported in IE8 standards mode reasons: standards compliance – issues fixed in IE8 performance security – "reduce browser attack surface" http://blogs.msdn.com/ie/archive/2008/10/16/ending-expressions.aspx but we'll still need to deal with IE6&7 for years to come

questions How do CSS expressions affect performance? What are two workarounds to this problem with CSS expressions?

Rule 8: Make JS and CSS External Browser Cache Expt: how much are resources cached? http://yuiblog.com/blog/2007/01/04/performance-research-part-2/ add transparent pixel image: <img src="image/blank.gif" height=1 width=1/> with specific headers: Expires: Thu, 15 Apr 2004 20:00:00 GMT Last-Modified: Wed, 22 Oct 2008 23:49:57 GMT requests from the browser will have one of these response status codes: 200 – the browser does not have the image in its cache 304 – the browser has the image in its cache, but needs to verify the last modified date

# unique users with at least one 200 response desired metrics What percentage of users view with an empty cache? # unique users with at least one 200 response total # unique users What percentage of page views are done with an empty cache? total # of 200 responses # of 200 + # of 304 responses

cache results 40-60% of users/day visit with an empty cache 75-85% of page views/day are primed cache

inline or external? OR OR <script type='text/javascript'> var favNumber = 128; </script> OR <script type='text/javascript' src='fav.js'></script> <style> #favNumber { font-weight: bold; } </style> OR <link rel='stylesheet' type='text/css' href='fav.css'>

doc size, # requests, cache empty cache primed cache png 10K html 50K png 10K html 50K inline 3 requests 70K faster 1 request 50K slower read from cache html 20K css 10K js 20K png 10K html 20K css 10K js 20K png 10K external 5 requests 70K slower 1 request 20K faster

inline or external? inline: faster, but HTML document is bigger external: more HTTP requests, but cached variables page views per user (per session) , external  empty cache stats , external  component re-use across pages , external  external is typically better main exception: home pages best of both worlds post-onload download dynamic inlining

post-onload download inline in front page download external files after onload window.onload = downloadComponents; function downloadComponents() { var elem = document.createElement("script"); elem.src = "http://.../file1.js"; var head = document.getElementsByTagName('head')[0]; head.appendChild(elem); ... } speeds up secondary pages

dynamic inlining start with post-onload download set cookie after components downloaded server-side: if cookie, use external else, do inline with post-onload download cookie expiration date is key speeds up initial and secondary pages

module boundaries fewer files are better – combine JS across all pages into one script? all CSS into one stylesheet? too much combining – a single page downloads more than it needs compromise define a few page "types", build JS and CSS modules for each page type define DHTML components, build JS and CSS modules for each component optimization – lazy-load modules for other pages from the landing page

questions What's a 200 status code? 304? If 40-60% of users come in with an empty cache once per day, why are only 15-25% of page views done with an empty cache? What's typically better, inlining or external? What are three variables to consider? Why are home pages the most likely candidates for inlining JS and CSS?

Rule 9: Reduce DNS Lookups typically take 20-100ms, sometimes > 500ms OS and browsers cache DNS resolutions

viewing DNS in Windows C:\>ipconfig /flushdns Windows IP Configuration Successfully flushed the DNS Resolver Cache. C:\>ipconfig /displaydns www.google.com ---------------------------------------- Record Name . . . . . : www.google.com Record Type . . . . . : 5 Time To Live . . . . : 43 Data Length . . . . . : 4 Section . . . . . . . : Answer CNAME Record . . . . : www.l.google.com

TTL (Time to Live) TTL < 30 minutes might not impact users www.amazon.com 1 minute www.aol.com www.cnn.com 10 minutes www.ebay.com 1 hour www.google.com 5 minutes www.msn.com www.myspace.com www.wikipedia.org www.yahoo.com www.youtube.com March 2007 TTL < 30 minutes might not impact users

browser DNS cache IE 7 Firefox 2 DnsCacheTimeout: 30 minutes KeepAliveTimeout: 1 minute ServerInfoTimeout: 2 minutes Firefox 2 network.dnsCacheExpiration: 1 minute network.dnsCacheEntries: 20 network.http.keep-alive.timeout: 5 minutes Fasterfox: 1 hour, 512 entries, 30 seconds

Reducing DNS Lookups use Keep-Alive adding DNS lookups vs. domain sharding identify dominant domain names, reduce non-dominant names for dominant domains – shard across 2-4 CNAMEs

questions How long does a DNS lookup typically take? What are three places where DNS resolutions are cached? What's a TTL? How do OSes and browsers (not) honor TTLs? What's the guideline for balancing DNS lookups and domain sharding?

Rule 10: Minify JavaScript minification: removing unnecessary characters from code (comments, white space, etc.) obfuscation: minify as well as reduce length of symbol names (munge)

original code event.js from YUI – http://developer.yahoo.com/yui/ YAHOO.util.CustomEvent = function(type, oScope, silent, signature) { this.type = type; this.scope = oScope || window; this.silent = silent; this.signature = signature || YAHOO.util.CustomEvent.LIST; this.subscribers = []; if (!this.silent) { } var onsubscribeType = "_YUICEOnSubscribe"; if (type !== onsubscribeType) { this.subscribeEvent = new YAHOO.util.CustomEvent(onsubscribeType, this, true); } }; event.js from YUI – http://developer.yahoo.com/yui/

minified code JSMin YUI Compressor YAHOO.util.CustomEvent=function(type,oScope,silent,signature){this.type=type;this.scope=oScope||window;this.silent=silent;this.signature=signature||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){} var_onsubscribeType="_YUICEOnSubscribe";if(type!==onsubscribeType){this.subscribeEvent=new_YAHOO.util.CustomEvent(onsubscribeType,this,true);}}; JSMin http://crockford.com/javascript/jsmin YUI Compressor http://developer.yahoo.com/yui/compressor/ also munges and minifies CSS

obfuscated code DoJo Compressor (ShrinkSafe) YUI Compressor YAHOO.util.CustomEvent=function(_1,_2,_3,_4){ this.type=_1; this.scope=_2||window; this.silent=_3; this.signature=_4||YAHOO.util.CustomEvent.LIST; this.subscribers=[]; if(!this.silent){ } var _5="_YUICEOnSubscribe"; if(_1!==_5){ this.subscribeEvent=new YAHOO.util.CustomEvent(_5,this,true); }; DoJo Compressor (ShrinkSafe) http://dojotoolkit.org/docs/shrinksafe/ YUI Compressor http://developer.yahoo.com/yui/compressor/

obfuscation costs obfuscation typically reduces size more, but has some costs bugs – symbol munged to "aa", namespace conflict maintenance – tag external symbols (eg, API) debugging – harder to read in production

minification vs. obfuscation Web Site Original Size After JSMin After ShrinkSafe amazon.com 204K 173K 156K aol.com 44K 40K cnn.com 98K 79K 74K myspace.com 88K 65K 64K wikipedia.org 42K 28K 26K youtube.com 34K 24K Average 85K 68K (-21%) 64K (-25%) minify – extra savings from obfuscation is not worth the risk

gzip and minification minify – obfuscation benefits decline with gzip Web Site Original Size After Gzip JSMIN & Gzip Shrink-Safe & Gzip amazon.com 204K 48K 41K 42K aol.com 44K 16K 15K cnn.com 98K 29K 23K myspace.com 88K 19K wikipedia.org 13K 8K youtube.com 34K 10K Average 85K 23K (-73%) 19K (-78%) minify – obfuscation benefits decline with gzip

Top 10 minification Minify External? Minify Inline? Apr 07 Oct 08 www.amazon.com yes www.aol.com some most www.cnn.com www.ebay.com froogle.google.com www.msn.com www.myspace.com www.wikipedia.org www.yahoo.com www.youtube.com

Minifying CSS savings are typically less compared to JavaScript not as much CSS as JavaScript CSS typically has fewer comments and whitespace greater savings from CSS optimizations merging identical rules abbreviations "#660066" => "#606" "0px" => "0" "background-color:" => "background:"

questions What's the difference between minification and obfuscation? How do they compare wrt reducing JavaScript size? What are three drawbacks to obfuscation?

Rule 11: Avoid Redirects 3xx status codes: "further action needs to be taken by the user agent in order to fulfill the request" 300 Multiple Choices (based on Content-Type) 301 Moved Permanently 302 Moved Temporarily (aka, Found) 303 See Other (clarification of 302) 304 Not Modified 305 Use Proxy 306 (no longer used) 307 Temporary Redirect (clarification of 302) http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3 most popular response for conditional GET request HTTP/1.1

redirect example go to the new location instead of the original one Request GET / HTTP/1.1 Host: astrology.yahoo.com Response HTTP/1.1 301 Moved Permanently Location: http://shine.yahoo.com/astrology/ go to the new location instead of the original one why use redirects? prettier URLs track traffic authentication

worst blocker inserting a redirect to the HTML document is worse than how stylesheets and scripts block all resources in the page are delayed the user gets very little feedback (nothing in the page) rendering, even the HTML text, is delayed 2nd worse – redirecting to a script

caching redirects "Moved Permanently" – is it cached? Request GET / HTTP/1.1 Host: astrology.yahoo.com Response HTTP/1.1 301 Moved Permanently Date: Tue, 28 Oct 2008 07:39:53 GMT Location: http://shine.yahoo.com/astrology/ Cache-Control: private Connection: close Transfer-Encoding: chunked Content-Type: text/html; charset=utf-8 "Moved Permanently" – is it cached? no spec: "cacheable if indicated by a Cache-Control or Expires header field"

caching: 301, 302, Expires past Expires no Expires future Expires 301 Moved Permanently don't cache: all IE, FF3, Safari, Opera cache: FF2, Chrome IE, FF3*, Safari, Opera 302 Moved Temporarily IE, FF3, Safari, Opera, Chrome FF2 past Expires no Expires future Expires 301 Moved Permanently don't cache: all IE, FF3, Safari, Opera cache: FF2, Chrome 302 Moved Temporarily IE, FF3, Safari, Opera, Chrome FF2 testing done 10/28/08 IE 7 & 8(beta 2), Firefox 2.0 & 3.0, Safari 4, Opera 9.61, Chrome 0.2 NOTE: this slide actually has TWO copies of the table, so that static slides show the table but animation reveals each column. FF2 and Chrome – only browsers to cache redirects *Firefox 3.1 fixes regression from FF2 to FF3

redirect alternatives JavaScript document.location = "destination.php"; what if JavaScript is disabled or not present? meta refresh – put in document's HEAD <meta http-equiv="refresh" content="0; url=destination.php"> in IE, causes conditional GET requests for all resources (similar to Reload button) # of seconds

cache workaround make this document cacheable! one last thing – need to let the page load so it can be cached <html> <head> <script type="text/javascript"> window.onload = function () { document.location = "destination.php"; } </script> <noscript> <meta http-equiv="refresh" content="0; url=destination.php"> </noscript> </head> one last thing – make this document cacheable!

redirects in the top 10 mostly ads # redirects www.aol.com 5 www.ebay.com www.facebook.com www.google.com/search search.live.com/results www.msn.com 1 www.myspace.com en.wikipedia.org/wiki www.yahoo.com 2 www.youtube.com mostly ads

common uses redirect from blah.com to www.blah.com missing trailing slash tracking internal traffic tracking outbound traffic prettier URLs, preserve old URLs connecting web sites ads authentication

use 1: www why redirect from http://aol.com/ to http://www.aol.com/? Request GET / HTTP/1.1 Host: aol.com Response HTTP/1.x 301 Moved Permanently Date: Tue, 28 Oct 2008 23:01:42 GMT Expires: Tue, 28 Oct 2008 23:31:42 GMT Location: http://www.aol.com/ why redirect from http://aol.com/ to http://www.aol.com/? set cookies on www domain – non-issue cache resources once regardless of which URL is used http://aol.com/logo.gif http://www.aol.com/logo.gif

use 1: www in the top 10 which top 10 sites redirect from blah.com to www.blah.com? status Expires aol.com 301 +30 mins ebay.com facebook.com July 1997 google.com +30 days search.live.com na msn.com myspace.com wikipedia.org 200 yahoo.com youtube.com 303 Apr 1971 how is this possible?! 303 See Other – "MUST NOT be cached"

use 1: www & Wikipedia all resources referenced via full URLs easy, if you're doing CDN domain sharding cookieless domain another alternative <base href="http://www.wikipedia.org">

use 2: missing trailing slash Request GET /msn HTTP/1.1 Host: astrocenter.astrology.msn.com Response HTTP/1.x 301 Moved Permanently Location: http://astrocenter.astrology.msn.com/msn/ reasons to redirect for missing trailing slash: autoindexing workaround: don't use autoindexing relative URLs for resources workaround: use base href, full URLs, or URLs relative to root

use 3: internal tracking Request GET /_ylt=Al…ume/**http%3A//tools.search.yahoo.com/about/forsearchers.html HTTP/1.1 Host: m.www.yahoo.com Response HTTP/1.x 302 Moved Temporarily Location: http://tools.search.yahoo.com/about/forsearchers.html "More" link on Yahoo! front page workaround: track referer [sic] on internal servers

use 4: outbound tracking Request GET /url?…url=http%3A%2F%2Fwww.npr.org/… HTTP/1.1 Host: www.google.com Response HTTP/1.x 302 Found Location: http://www.npr.org/ clicking on a Google search result workarounds: image beacon – race conditions XMLHttpRequest readyState 2 – faster, more complex HTML 5 <a ping="http://..."> <link rel=pingback href="http://...">

use 5: prettier URLs Request GET / HTTP/1.1 Host: music.myspace.com Response HTTP/1.x 302 Moved Location: http://profile.myspace.com/index.cfm?fuseaction=music prettier URLs are easier to remember also, preserve old URLs when code changes workaround: mod_rewrite, cacheable redirects

use 6: connecting sites http://toolbar.google.com/ http://toolbar.google.com/index.html http://toolbar.google.com/T5/ http://toolbar.google.com/T5/intl/en/index.html http://www.google.com/tools/firefox/toolbar/F T3/intl/en/index.html redirects are an easy way to "integrate" separate teams (T4, T5), separate code bases (IE, FF), separate servers (toolbar, www) workarounds: CNAMEs, mod_rewrite

use 7: ads specifically, counting ad impressions advertisers and publishers have a hard time reconciling the count when do you count an ad impression? when a page containing an ad is served? what if the page never arrives? when a page containing an ad arrives at the client? what if the ad request fails, or the user stops the page? when the content of the ad (image, Flash) is requested from the advertiser? what if the user leaves the page before the content arrives? after the content arrives? is it the publisher's fault if the content is slow?

use 7: ads how do you count an ad impression? when a page containing an ad is served? count it on the publisher's backend when a page containing an ad arrives at the client? send a beacon from the client when the content of the ad (image, Flash) is requested from the advertiser? count it on the advertiser's backend after the content arrives? redirects can help count when content is served and reconcile the two parties

use 7: ads from http://www.aol.com/ double logging? http://ad.doubleclick.net/im…5|1;;cs=o%3fhttp://ad.doubleclick.net/dot.gif?258824979 http://ad.doubleclick.net/dot.gif?258824979 http://eatps.web.aol.com:9000/open_web_adhoc?subtype=40…458 http://www.aolcdn.com/pops_promo/pixel http://ad.doubleclick.net/ad/N553.AEAOLService/B2775919.11;dcadv=1297440;sz=1x1;ord=4613012? http://m1.2mdn.net/viewad/1297440/1x1.gif from http://www.aol.com/ double logging?

use 7: ads from http://www.cnn.com/ double logging? http://ads.cnn.com/event.ng/Type=count&Clie…ARd http://i.cdn.turner.com/cnn/images/1.gif http://ad.doubleclick.net/ad/N3880.SD146.3880/B3107454.25;dcove=o;sz=1x1;ord=dwgksue,beqpWcytARh? http://m1.2mdn.net/viewad/1139835/67-1x1.gif from http://www.cnn.com/ double logging?

use 8: authentication cookies are used for authentication cookies can only be set on the page's domain how authenticate someone on domain A if they're currently on domain B? redirects authentication is often on https servers how authenticate someone on https if they're currently on http?

use 8: authentication https://www.google.com/accounts/ServiceLoginBoxAuth https://www.google.com/accounts/CheckCookie?con tinue=http%3A%2F%2Fgroups.google.com%2Fgroups %2Fauth%3F_done… http://groups.google.com/groups/auth?_done… http://groups.google.com/ one reason why redirects with Set-Cookie are sometimes not cached

avoid redirects eliminate the need make them cacheable base href or full URLs for resources referer tracking HTML 5 – A ping and LINK pingback CNAMEs mod_rewrite no autoindex make them cacheable 301 with future Expires JavaScript & meta refresh with future Expires

questions What's the status text for 301 and 302? What HTTP response header contains the URL the user is redirected to? Why are redirects worse than stylesheets and scripts in terms of blocking? If a redirect is "Moved Permanently", does that mean it's cached? Which browsers today cache redirects? What are two other techniques for doing redirects? How can they be used to make redirects cacheable?

Rule 12: Remove Duplicate Scripts hurts performance extra HTTP requests if not cacheable http://stevesouders.com/hpws/dupe-scripts.php IE and FF extra executions http://stevesouders.com/hpws/dupe-scripts-cached10.php all browsers atypical? happens with ads http://www.aol.com/ adsonar.js (6K) loaded six times happens with iframes http://www.ossamples.com/recipes/ fc-os-ext.js (15K), gadgets_en.js (155K) each loaded 3 times

script insertion Functions <?php function insertScript($jsfile) { if ( alreadyInserted($jsfile) ) { return; } pushInserted($jsfile); if ( hasDependencies($jsfile) ) { $dependencies = getDependencies($jsfile); for ( $i = 0; $i < count($dependencies); $i++ ) { insertScript($dependencies[$i]); } echo '<script type="text/javascript" src="' . getVersion($jsfile) . '"></script>"; ?> avoids dupes, makes sure dependencies are included in the right order, handles versioning could do combining

questions What are two typical causes of duplicate scripts? In what way(s) can duplicate scripts be bad for performance?

Rule 13: Configure ETags Expires and Last-Modified GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 Accept-Encoding: gzip,deflate HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 2066 Content-Encoding: gzip Expires: Fri, 26 Sep 2008 22:00:00 GMT XmoÛHþ\ÿFÖvã*wØoq... HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 2066 Content-Encoding: gzip XmoÛHþ\ÿFÖvã*wØoq... expiration date determines freshness can also use Cache-Control:max-age

Conditional GET (IMS) GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 Accept-Encoding: gzip,deflate If-Modified-Since: Mon, 22 Sep 2008 21:14:35 GMT HTTP/1.1 304 Not Modified IMS determines validity – does the browser's cached version match what's on the server? the comparison is based on the resource's date a 304 response is sent instead of all the data IMS is used when Reload is pressed

ETag response header GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 Accept-Encoding: gzip,deflate HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 2066 Content-Encoding: gzip Expires: Fri, 26 Sep 2008 22:00:00 GMT ETag: "19f1e-7920-4525b037f0440" XmoÛHþ\ÿFÖvã*wØoq... HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Mon, 22 Sep 2008 21:14:35 GMT Content-Length: 2066 Content-Encoding: gzip XmoÛHþ\ÿFÖvã*wØoq...

Conditional GET (INM) alternative way to test validity GET /v-app/scripts/107652916-dom.common.js HTTP/1.1 Host: www.blogger.com User-Agent: Mozilla/5.0 (…) Gecko/2008070208 Firefox/3.0.1 Accept-Encoding: gzip,deflate If-Modified-Since: Mon, 22 Sep 2008 21:14:35 GMT If-None-Match: "19f1e-7920-4525b037f0440" HTTP/1.1 304 Not Modified alternative way to test validity

what is an ETag? added in HTTP/1.1 http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11 added in HTTP/1.1 used by clients and servers to validate expired resources more flexible than Last-Modified date "An entity tag consists of an opaque quoted string" " An entity tag MUST be unique across all versions of all entities associated with a particular resource."

If-None-Match (hit) http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26 "If any of the entity tags match the entity tag of the entity that would have been returned in the response to a similar GET request (without the If-None-Match header) on that resource[…], then the server MUST NOT perform the requested method, unless required to do so because the resource's modification date fails to match that supplied in an If-Modified-Since header field in the request. Instead, if the request method was GET or HEAD, the server SHOULD respond with a 304 (Not Modified) response,…"

INM, IMS hit & miss hit miss 304 full response If-Modified- Since If-None-Match

If-None-Match (miss) If none of the entity tags match, then the server MAY perform the requested method as if the If-None-Match header field did not exist, but MUST also ignore any If-Modified-Since header field(s) in the request. That is, if no entity tags match, then the server MUST NOT return a 304 (Not Modified) response.

INM, IMS hit & miss hit miss 304 full response If-Modified- Since If-None-Match if not managed properly, sending both IMS and INM lowers the chances of a simple, small 304 response How could it not be managed properly?!

Apache ETags "19f1e-7920-4525b037f0440" "inode-size-timestamp" inode – used by filesystems to store file type, owner, group, permissions, etc. inode for the same file differs across servers even if file size, timestamp, and directory is the same http://stevesouders.com/images/arrow-right-9x13.png ETag: "21f5315-d4-5d51f0c0" http://1.cuzillion.com/images/arrow-right-9x13.png ETag: "1ee57ec-d4-5d51f0c0"

IIS ETags changenumber – counter to track IIS configuration changes "b4f35327edac51:113f" "timestamp:changenumber" changenumber – counter to track IIS configuration changes changenumber rarely the same across servers http://hp.msn.com/global/c/hpv10/favicon.ico ETag: "b4f35327edac51:113f" ETag: "b4f35327edac51:e6e"

example ETag miss GET /global/c/hpv10/favicon.ico HTTP/1.1 Host: hp.msn.com If-Modified-Since: Wed, 26 Oct 2005 22:39:58 GMT If-None-Match: "b4f35327edac51:19bc" HTTP/1.x 200 OK Content-Length: 1406 Etag: "b4f35327edac51:d76" Last-Modified: Wed, 26 Oct 2005 22:39:58 GMT Expires: Wed, 06 Feb 2008 01:10:16 GMT Last-Modified matches (but IMS misses) timestamp is the same changenumber differs, validations misses, entire body is resent validation miss

the problem with ETags the default ETag syntax in Apache and IIS makes it unlikely that INM will match across servers, even when the resource is the same probability of an incorrect INM miss: (n-1)/n where "n" is the number of servers not an issue if you just have one server http://www.apacheweek.com/issues/02-01-18 "can cause an unnecessary performance hit as resources are fetched more often than is required" http://support.microsoft.com/kb/922703 "IIS 6.0 sends a 200 response because it considers the different change numbers to mean that [the resources] are not the same versions"

the solution for ETags if you're not leveraging ETags, turn them off reduces size of requests and responses reduces outbound traffic from your servers increases proxy cache hit rate Apache: FileETag none IIS: synchronize changenumber across servers http://support.microsoft.com/kb/922703/

ETags in the wild server ETags? default syntax? www.aol.com AOLserver no – www.ebay.com IIS yes www.facebook.com Apache www.google.com/search gws search.live.com/results ASP.NET www.msn.com www.myspace.com some en.wikipedia.org/wiki lighthttpd ? www.yahoo.com YTS www.youtube.com btfe

possible uses for ETags ???

questions Why were ETags introduced in HTTP/1.1? What do "IMS" and "INM" stand for? How do IMS and INM interplay during resource validation? What component in the default ETag syntax hurts performance in Apache and IIS, and why? What are three performance gains you can achieve by turning off ETags?

Rule 14: Make Ajax Cacheable communities rich UI mashups JS, CSS, & DOM used to modify the page Asynchronous JS and XML layer between data and UI

async == instantaneous (?) try Google Maps on dialup passive Ajax requests in anticipation of user's needs e.g., download address book for webmail active Ajax requests in response to user action e.g., email search request user is waiting; not instantaneous optimize these first

Ajax optimizations add an Expires header gzip components minify JavaScript avoid redirects configure ETags most important

cache Ajax? really?! but... it's dynamic it's data it's private yes, but for this [user | time | browser] it's [always the same | doesn't change for awhile] it's data sometimes data doesn't change it's private :no-store doesn't always work should you use https?

caching XHR vs. HTML XHR and HTML often contain dynamic, personalized data why can I cache XHR, but not HTML? the URL for HTML is often frozen bookmarks cross-references prettier memorized developers control what's in XHR URLs the XHR URL is contained inside the HTML the developer can modify the XHR URL with data to avoid a cache hit

ex: Google Calendar http://www.google.com/calendar/contacts solution: HTTP/1.x 200 OK Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Content-Type: text/javascript; charset=UTF-8 Content-Encoding: gzip Date: Mon, 10 Nov 2008 22:00:57 GMT Content-Length: 1562 solution: add modification timestamp to URL http://www.google.com/calendar/contacts_1226354800

questions Which performance rules so far apply to Ajax? What are passive Ajax requests? active? Why may developers view the cacheability of Ajax responses differently than other content? If I can cache XHRs, why can't I cache HTML that also contains dynamic data?

LUNCH!

morning wrap-up EFWS 1-4 break EFWS 5-8 performance analysis state of performance

morning wrap-up EFWS 1-4 break EFWS 5-8 performance analysis state of performance

September 2007

June 2009

Even Faster Web Sites Splitting the initial payload Loading scripts without blocking Coupling asynchronous scripts Positioning inline scripts Sharding dominant domains Flushing the document early Using iframes sparingly Simplifying CSS Selectors Understanding Ajax performance Doug Crockford Writing efficient JavaScript Nicholas Zakas Creating responsive web apps Ben Galbraith, Dion Almaer Scaling with Comet Dylan Schiemann Going Beyond Gzipping Tony Gentilcore Optimizing Images Stoyan Stefanov, Nicole Sullivan

why focus on JavaScript? Yahoo! YouTube AOL Wikipedia eBay Facebook MySpace Data Source: Steve Souders aol 76% ebay 45% facebook 41% google 42% live search 9% msn 37% myspace 37% yahoo 45% youtube 60% wikipedia 26% average 42%

scripts block <script src="A.js"> blocks parallel downloads and rendering http://stevesouders.com/cuzillion/?ex=10008

Cuzillion 'cuz there are a zillion pages to check a tool for quickly constructing web pages to see how components interact Open Source http://stevesouders.com/cuzillion/

initial payload and execution JavaScript Functions Executed before onload www.aol.com 115K 30% www.ebay.com 183K 44% www.facebook.com 1088K 9% www.google.com/search 15K 45% search.live.com/results 17K 24% www.msn.com 131K 31% www.myspace.com 297K 18% en.wikipedia.org/wiki 114K 32% www.yahoo.com 321K 13% www.youtube.com 240K Data source: Steve Souders 252K avg 26% avg

the other 74% what's the other ~74% of JavaScript for? conditional blocks – errors, specific browsers, edge cases DHTML features – dynamic menus, popup DIVs, XHR cruft! given the blocking nature of JavaScript, it's painful to slowdown the page for JavaScript that may never be used

Splitting the initial payload split your JavaScript between what's needed to render the page and everything else load "everything else" after the page is rendered separate manually (Firebug); tools needed to automate this (Doloto from Microsoft) load scripts without blocking – how? Permission to use photo given by Brian.H - http://flickr.com/photos/robinofloxley/750220669/

questions What's the average size of JavaScript downloaded by the Alexa top ten? On average how much of that is executed before onload? Why is this measurement done at the onload event? Why is there so much JavaScript that's not called before onload? What does "lazy load" mean? How do you lazy load a script?

MSN.com: parallel scripts Scripts and other resources downloaded in parallel! How? Secret sauce?! var p= g.getElementsByTagName("HEAD")[0]; var c=g.createElement("script"); c.type="text/javascript"; c.onreadystatechange=n; c.onerror=c.onload=k; c.src=e; p.appendChild(c) Of the ten top sites, MSN.com (Script DOM Element), Live Search (Script in Iframe), and Yahoo (Script DOM Element) use advanced script loading techniques.

Loading Scripts Without Blocking XHR Eval XHR Injection Script in Iframe Script DOM Element Script Defer document.write Script Tag All of these allow for parallel downloads, but none of them allow for parallel JS execution – that's not possible (currently, WebKit is doing some stuff on that).

XHR Eval script must have same domain as main page var xhrObj = getXHRObject(); xhrObj.onreadystatechange = function() { if ( xhrObj.readyState != 4 ) return; eval(xhrObj.responseText); }; xhrObj.open('GET', 'A.js', true); xhrObj.send(''); script must have same domain as main page must refactor script http://stevesouders.com/cuzillion/?ex=10009

XHR Injection script must have same domain as main page var xhrObj = getXHRObject(); xhrObj.onreadystatechange = function() { if ( xhrObj.readyState != 4 ) return; var se=document.createElement('script'); document.getElementsByTagName('head') [0].appendChild(se); se.text = xhrObj.responseText; }; xhrObj.open('GET', 'A.js', true); xhrObj.send(''); script must have same domain as main page http://stevesouders.com/cuzillion/?ex=10015

Script in Iframe iframe must have same domain as main page <iframe src='A.html' width=0 height=0 frameborder=0 id=frame1></iframe> iframe must have same domain as main page must refactor script: // access iframe from main page window.frames[0].createNewDiv(); // access main page from iframe parent.document.createElement('div'); http://stevesouders.com/cuzillion/?ex=10012

Script DOM Element script and main page domains can differ var se = document.createElement('script'); se.src = 'http://anydomain.com/A.js'; document.getElementsByTagName('head')[0].appendChild(se); script and main page domains can differ no need to refactor JavaScript http://stevesouders.com/cuzillion/?ex=10010

Script Defer only supported in IE (just landed in FF 3.1) <script defer src='A.js'></script> only supported in IE (just landed in FF 3.1) script and main page domains can differ no need to refactor JavaScript http://stevesouders.com/cuzillion/?ex=10013

document.write Script Tag document.write("<script type='text/javascript' src='A.js'> <\/script>"); parallelization only works in IE parallel downloads for scripts, nothing else all document.writes must be in same script block http://stevesouders.com/cuzillion/?ex=10014

browser busy indicators Audio (IE "click") is another busy indicator. Delayed rendering and delayed onload ("done") are other busy indicators. Sometimes busy indicators are bad, sometimes good.

browser busy indicators status bar progress logo cursor block render onload normal Script Src FF IE,FF XHR Eval no XHR Injection Script in Iframe Script DOM Element Script Defer document.write Script Tag Data source: Steve Souders Audio (IE "click") is another busy indicator. Delayed rendering and delayed onload ("done") are other busy indicators. Sometimes busy indicators are bad, sometimes good. good to show busy indicators when the user needs feedback bad when downloading in the background

ensure/avoid ordered execution Ensure scripts execute in order: necessary when scripts have dependencies IE: http://stevesouders.com/cuzillion/?ex=10017 FF: http://stevesouders.com/cuzillion/?ex=10018 Avoid scripts executing in order: faster – first script back is executed immediately http://stevesouders.com/cuzillion/?ex=10019

asynchronous loading traits || down-loads domains can differ existing scripts browser busy ensures order size (bytes) normal Script Src no yes IE,FF ~50 XHR Eval ~500 XHR Injection Script in Iframe Script DOM Element FF ~200 Script Defer IE document.write Script Tag IE* ~100 Data source: Steve Souders *Only other document.write scripts are downloaded in parallel (in the same script block).

and the winner is... XHR Eval XHR Injection Script in iframe Script DOM Element Script Defer Script DOM Element (FF) Script Defer (IE) Script DOM Element (IE) Managed XHR Injection Managed XHR Eval different domains same domains no order preserve order no busy show busy I'll do JavaScript and PHP implementations of this logic soon.

ads and async scripts many ads load external scripts why can't these scripts be loaded using these non-blocking techniques? they use document.write if a script containing document.write is loaded asynchronously, the entire page is erased: http://stevesouders.com/tests/delayed-script-execution.php (click on "Load Dynamically") an alternative: Opera's "Delayed Script Execution"

Opera delayed scripts opera:config#Extensions|DelayedScriptExecution delays (defers) script loading with some nice enhancements deferred to the very end remembers script location so document.write still works huge improvement for ads prototype for future implementation of defer http://www.stevesouders.com/blog/2008/09/11/delayed-script-execution-in-opera/

Loading Scripts Without Blocking don't let scripts block other downloads you can still control execution order, busy indicators, and onload event what about inlined code dependencies? Permission to use photo given by Reciprocity: http://flickr.com/photos/alanjaras/76000107/

questions If you could only use one technique, which would you pick? Why? Why is executing scripts out of order faster? Which of the techniques does block rendering? What happens if an external script loaded asynchronously does document.write?

synchronous JS example: menu.js <script src="menu.js" type="text/javascript"></script> <script type="text/javascript"> var aExamples = [ ['couple-normal.php', 'Normal Script Src'], ['couple-xhr-eval.php', 'XHR Eval'], ... ['managed-xhr.php', 'Managed XHR'] ]; function init() { EFWS.Menu.createMenu('examplesbtn', aExamples); } init(); </script>

asynchronous JS example: menu.js script DOM element approach <script type="text/javascript"> var domscript = document.createElement('script'); domscript.src = "menu.js"; document.getElementsByTagName('head')[0] .appendChild(domscript); var aExamples = [ ['couple-normal.php', 'Normal Script Src'], ['couple-xhr-eval.php', 'XHR Eval'], ... ['managed-xhr.php', 'Managed XHR'] ]; function init() { EFWS.Menu.createMenu('examplesbtn', aExamples); } init(); </script>

before after

asynchronous loading traits || down-loads domains can differ existing scripts browser busy ensures order size (bytes) normal Script Src no yes IE,FF ~50 XHR Eval ~500 XHR Injection Script in Iframe Script DOM Element FF ~200 Script Defer IE document.write Script Tag IE* ~100 !IE Data source: Steve Souders *Only other document.write scripts are downloaded in parallel (in the same script block).

that depends on the script? what about inlined code that depends on the script?

baseline coupling results (not good) Preserve Execution Order Load Script & Image in Parallel normal Script Src all IE8, Saf4, Chr2 XHR Eval - XHR Injection Script in Iframe Script DOM Element FF, Op IE, FF, Saf, Chr Script Defer FF, Saf, Chr, Op IE, (Saf4, Chr2) * document.write Script Tag Saf4, Chr2 Newer browsers (IE8, Saf4, Chr2) work, but mainstream browsers need a workaround. need a way to load scripts asynchronously AND preserve order * Scripts download in parallel regardless of the Defer attribute.

Coupling Asynchronous Scripts hardcoded callback window onload timer degrading script tags script onload

technique 1: hardcoded callback <script type="text/javascript"> var aExamples = [['couple-normal.php', 'Normal Script Src'], ...]; function init() { EFWS.Menu.createMenu('examplesbtn', aExamples); } var domscript = document.createElement('script'); domscript.src = "menu.js"; document.getElementsByTagName('head')[0].appendChild(domscript); </script> init() is called from within menu.js not very flexible doesn't work for 3rd party scripts

technique 2: window onload <iframe src="menu.php" width=0 height=0 frameborder=0> </iframe> <script type="text/javascript"> var aExamples = [['couple-normal.php', 'Normal Script Src'], ...]; function init() { EFWS.Menu.createMenu('examplesbtn', aExamples); } if ( window.addEventListener ) { window.addEventListener("load", init, false); else if ( window.attachEvent ) { window.attachEvent("onload", init); </script> init() is called at window onload must use async technique that blocks onload: Script in Iframe does this across most browsers init() called later than necessary

technique 3: timer load if interval too low, delay if too high <script type="text/javascript"> var domscript = document.createElement('script'); domscript.src = "menu.js"; document.getElementsByTagName('head')[0].appendChild(domscript); var aExamples = [['couple-normal.php', 'Normal Script Src'], ...]; function init() { EFWS.Menu.createMenu('examplesbtn', aExamples); } function initTimer(interval) { if ( "undefined" === typeof(EFWS) ) { setTimeout(initTimer, interval); else { init(); initTimer(300); </script> load if interval too low, delay if too high slight increased maintenance – EFWS

John Resig's degrading script tags <script src="menu-degrading.js" type="text/javascript"> var aExamples = [['couple-normal.php', 'Normal Script Src'], ...]; function init() { EFWS.Menu.createMenu('examplesbtn', aExamples); } init(); </script> at the end of menu-degrading.js: var scripts = document.getElementsByTagName("script"); var cntr = scripts.length; while ( cntr ) { var curScript = scripts[cntr-1]; if (curScript.src.indexOf("menu-degrading.js") != -1) { eval( curScript.innerHTML ); break; } cntr--; putting code in the script block doesn't work in any browser; you have to add stuff to the external script this doesn't load asynchronously cleaner clearer safer – inlined code not called if script fails no browser supports it http://ejohn.org/blog/degrading-script-tags/

technique 4: degrading script tags <script type="text/javascript"> var aExamples = [['couple-normal.php', 'Normal Script Src'],...]; function init() { EFWS.Menu.createMenu('examplesbtn', aExamples); } var domscript = document.createElement('script'); domscript.src = "menu-degrading.js"; if ( -1 != navigator.userAgent.indexOf("Opera") ) { domscript.innerHTML = "init();"; else { domscript.text = "init();"; document.getElementsByTagName('head')[0].appendChild(domscript); </script> elegant, flexible (cool!) not well known doesn't work for 3rd party scripts (unless...)

technique 5: script onload <script type="text/javascript"> var aExamples = [['couple-normal.php', 'Normal Script Src'], ...]; function init() { EFWS.Menu.createMenu('examplesbtn', aExamples); } var domscript = document.createElement('script'); domscript.src = "menu.js"; domscript.onloadDone = false; domscript.onload = function() { if ( ! domscript.onloadDone ) { init(); } domscript.onloadDone = true; }; domscript.onreadystatechange = function() { if ( "loaded" === domscript.readyState ) { document.getElementsByTagName('head')[0].appendChild(domscript); </script> pretty nice, medium complexity

multiple scripts and inlined code what about that depend on each other, and inlined code that depends on the scripts? two solutions: Managed XHR DOM Element and Doc Write

multiple script example: menutier.js <script src="menu.js" type="text/javascript"></script> <script src="menutier.js" type="text/javascript"></script> <script type="text/javascript"> var aRaceConditions = [['couple-normal.php', 'Normal...]; var aWorkarounds = [['hardcoded-callback.php', 'Hardcod...]; var aMultipleScripts = [['managed-xhr.php', 'Managed XH...]; var aLoadScripts = [['loadscript.php', 'loadScript'], ...]; var aSubmenus = [["Race Conditions", aRaceConditions], ["Workarounds", aWorkarounds], ["Multiple Scripts", aMultipleScripts], ["General Solution", aLoadScripts]]; function init() { EFWS.Menu.createTieredMenu('examplesbtn', aSubmenus); } </script>

technique 1: managed XHR <script type="text/javascript"> var aRaceConditions = [['couple-normal.php', 'Normal...]; var aWorkarounds = [['hardcoded-callback.php', 'Hardcod...]; var aMultipleScripts = [['managed-xhr.php', 'Managed XH...]; var aLoadScripts = [['loadscript.php', 'loadScript'], ...]; var aSubmenus = [["Race Conditions", aRaceConditions], ...]; function init() { EFWS.Menu.createTieredMenu('examplesbtn', aSubmenus); } EFWS.Script.loadScriptXhrInjection("menu.js", null, true); EFWS.Script.loadScriptXhrInjection("menutier.js", init, true); </script> XHR Injection asynchronous technique does not preserve order – we have to add that before after

EFWS.loadScriptXhrInjection // Load an external script. // Optionally call a callback and preserve order. loadScriptXhrInjection: function(url, onload, bOrder) { var iQ = EFWS.Script.queuedScripts.length; if ( bOrder ) { var qScript = { response: null, onload: onload, done: false }; EFWS.Script.queuedScripts[iQ] = qScript; } var xhrObj = EFWS.Script.getXHRObject(); xhrObj.onreadystatechange = function() { if ( xhrObj.readyState == 4 ) { EFWS.Script.queuedScripts[iQ].response = xhrObj.responseText; EFWS.Script.injectScripts(); else { eval(xhrObj.responseText); if ( onload ) { onload(); }; xhrObj.open('GET', url, true); xhrObj.send(''); add to queue (if bOrder) save response to queue process queue (next slide) or... eval now, call callback

EFWS.injectScripts preserves external script order non-blocking // Process queued scripts to see if any are ready to inject. injectScripts: function() { var len = EFWS.Script.queuedScripts.length; for ( var i = 0; i < len; i++ ) { var qScript = EFWS.Script.queuedScripts[i]; if ( ! qScript.done ) { if ( ! qScript.response ) { // STOP! need to wait for this response break; } else { eval(qScript.response); if ( qScript.onload ) { qScript.onload(); qScript.done = true; if not yet injected bail – need to wait to preserve order ready for this script, eval and call callback preserves external script order non-blocking couples with inlined code works in all browsers works with scripts across domains works with scripts across domains

technique 2: DOM Element and Doc Write Preserve Execution Order Load Scripts in Parallel Load Script & Image in Parallel Script DOM Element FF, Op FF, Op, IE, Saf, Chr FF, IE, Saf, Chr Script Defer IE, Saf, Chr, FF, Op IE document.write Script Tag IE, Op Newer browsers (IE8, Saf4, Chr2) work, but mainstream browsers need a workaround. Firefox & Opera – use Script DOM Element IE – use document.write Script Tag Safari, Chrome – no benefit; rely on Safari 4 and Chrome 2

EFWS.loadScripts loadScripts: function(aUrls, onload) { // first pass: see if any of the scripts are on a different domain var nUrls = aUrls.length; var bDifferent = false; for ( var i = 0; i < nUrls; i++ ) { if ( EFWS.Script.differentDomain(aUrls[i]) ) { bDifferent = true; break; } // pick the best loading function var loadFunc = EFWS.Script.loadScriptXhrInjection; if ( bDifferent ) { if ( -1 != navigator.userAgent.indexOf('Firefox') || -1 != navigator.userAgent.indexOf('Opera') ) { loadFunc = EFWS.Script.loadScriptDomElement; else { loadFunc = EFWS.Script.loadScriptDocWrite; // second pass: load the scripts loadFunc(aUrls[i], ( i+1 == nUrls ? onload : null ), true);

multiple scripts with dependencies <script type="text/javascript"> var aRaceConditions = [['couple-normal.php', 'Normal...]; var aWorkarounds = [['hardcoded-callback.php', 'Hardcod...]; var aMultipleScripts = [['managed-xhr.php', 'Managed XH...]; var aLoadScripts = [['loadscript.php', 'loadScript'], ...]; var aSubmenus = [["Race Conditions", aRaceConditions], ...]; function init() { EFWS.Menu.createTieredMenu('examplesbtn', aSubmenus); } EFWS.Script.loadScripts(["menu.js", "menutier.js"], init); </script> scripts on same domain: order preserved, no blocking scripts on different domain: order preserved: all loads scripts in parallel: all except Saf3, Chr1 load script and image in parallel: FF, Saf4, Chr2

asynchronous scripts wrap-up Technique Preserve Order Load Scripts in Parallel Load Script & Image in Parallel single script Script DOM Element na all multiple scripts, no dependencies multiple scripts, dependencies, same domain Managed XHR Script DOM Element (FF, Op), Doc Write (IE, Saf, Chr) !Saf3, !Chr1 FF, Saf4, Chr2 Newer browsers (IE8, Saf4, Chr2) work, but mainstream browsers need a workaround.

case study: Google Analytics recommended pattern:* <script type="text/javascript"> var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); </script> var pageTracker = _gat._getTracker("UA-xxxxxx-x"); pageTracker._trackPageview(); document.write Script Tag approach blocks other resources * http://www.google.com/support/analytics/bin/answer.py?hl=en&answer=55488

case study: dojox.analytics.Urchin* _loadGA: function(){ var gaHost = ("https:" == document.location.protocol) ? "https://ssl." : "http://www."; dojo.create('script', { src: gaHost + "google-analytics.com/ga.js" }, dojo.doc.getElementsByTagName("head")[0]); setTimeout(dojo.hitch(this, "_checkGA"), this.loadInterval); }, _checkGA: function(){ setTimeout(dojo.hitch(this, !window["_gat"] ? "_checkGA" : "_gotGA"), this.loadInterval); _gotGA: function(){ this.tracker = _gat._getTracker(this.acct); ... } Script DOM Element approach "timer" coupling technique (script onload better) loadInterval is 420 ms * http://docs.dojocampus.org/dojox/analytics/Urchin

asynchronous loading & coupling async technique: Script DOM Element easy, cross-browser doesn't ensure script order coupling technique: script onload fairly easy, cross-browser ensures execution order for external script and inlined code

questions How can you load an external script asynchronously, and have an inline script execute as soon as the external script is loaded?

bad: stylesheet followed by inline script browsers download stylesheets in parallel with other resources that follow... ...unless the stylesheet is followed by an inline script http://stevesouders.com/cuzillion/?ex=10021 best to move inline scripts above stylesheets or below other resources Joseph Smarr from Plaxo advocates interspersing setTimeout through JavaScript threads every n00 ms.

stylesheets – ensuring order browsers download stylesheets in parallel with other resources* http://stevesouders.com/cuzillion/?c0=hc1hfff2_0&c1=hc1hfff2_0&c2=bi1hfff2_0&c3=bf1hfff2_0&c4=bj1hfff2_0 stylesheets are applied in the order specified, regardless of download order http://stevesouders.com/hpws2/stylesheets-order.php same for stylesheets and inline styles http://stevesouders.com/hpws2/css-order.php what about stylesheets and inline scripts? * except Firefox 2

Positioning Inline Scripts long executing inline scripts block rendering and downloads of everything after them in the page http://stevesouders.com/cuzillion/?c0=bi1hfff1_0&c1=bb0hfff0_5&c2=bi1hfff1_0 workarounds: initiate execution with setTimeout (>250 for FF, nglayout.initialpaint.delay) move JavaScript to external script with advanced downloading techniques use Defer attribute (IE only) make code re-entrant, call setTimeout every 300ms

inline script parallelization resources that occur before an inline script download in parallel while the script executes http://stevesouders.com/cuzillion/?c0=bi1hfff2_0&c1=bb0hfff0_1&c2=bf2hfff2_0&c3=bb0hfff0_1&c4=bi3hfff2_0 ...except for stylesheets http://stevesouders.com/cuzillion/?c0=bc1hfff2_0&c1=bb0hfff0_1&c2=bc2hfff2_0&c3=bb0hfff0_1&c4=bi3hfff2_0 why?! CSS and JavaScript might have interdependencies getElementsByClassName (HTML 5) how might this affect stylesheet and inline script download parallelization?

stylesheet, inline script block downloading browsers download stylesheets in parallel with other resources* ...unless the stylesheet is followed by an inline script http://stevesouders.com/cuzillion/?ex=10021 best to move inline scripts above stylesheets or below other resources * except Firefox 2 Joseph Smarr from Plaxo advocates interspersing setTimeout through JavaScript threads every n00 ms.

examples of scattered scripts Wikipedia MySpace eBay MSN Data source: Steve Souders

Positioning Inline Scripts remember inline scripts carry a cost avoid long-executing inline scripts don't put inline scripts between stylesheets and other resources Permission to use photo given by _iosonoshuo_: http://flickr.com/photos/10486436@N00/2055807701/

questions What do inline scripts block? How can you workaround this blocking? What's the unusual behaviour of a stylesheet, inline script, and image (in that order)? What would explain why browser developers implemented this behaviour?

morning wrap-up EFWS 1-4 break EFWS 5-8 performance analysis state of performance

morning wrap-up EFWS 1-4 break EFWS 5-8 performance analysis state of performance

Sharding Dominant Domains HTTP/1.1 and older browsers 2 connections per server based on name, not IP includes IE 6,7 "domain sharding" intentionally splitting resources across multiple domains makes pages load faster

Sharding Dominant Domains but Rule 9 says "Reduce DNS lookups"?! remove DNS lookups that aren't heavily used split domains that are on the critical path how find "critical path"?

www.yahoo.com

news.google.com http://news.google.com

downgrading to HTTP/1.0 HTTP/1.1 – 2 connections/server HTTP/1.0 – 4 (IE 6,7), 8 (FF2) conns HTTP/1.1 has fewer connections because persistent connections are on by default best for static content example: http://wikipedia.org/

newer browsers newer browsers open more connections HTTP/1.1 HTTP/1.0 IE 6,7 2 4 IE 8 6 Firefox 1.5, 2 8 Firefox 3 Safari 3,4 Chrome ? Opera 9 newer browsers open more connections http://www.stevesouders.com/blog/2008/03/20/roundup-on-parallel-connections/

how many domains? 2-4 is optimal http://yuiblog.com/blog/2007/04/11/performance-research-part-4/ 2-4 is optimal after 4 domains, response time degrades more DNS lookups thrashing on client

questions What's "domain sharding"? Why would downgrading to HTTP/1.0 be faster? Should I do that for all responses? Why would the HTTP/1.1 spec suggest fewer connections per server? What's the # of connections per server for popular browsers? What's the optimal number of domains to shard across?

Flushing the Document Early html image script html image script call PHP's flush() start the browser working before the HTML document is even completed makes sense for pages with long backend time (exceptions to the Performance Golden Rule) gives users feedback sooner starts downloads earlier

where to flush after a few resources after some content the user will see before the backend part that is slow

flushing gotchas PHP output_buffering – ob_flush() Transfer-Encoding: chunked gzip – Apache's DeflateBufferSize before 2.2.8 proxies and anti-virus software browsers – IE (255b), Safari (1K), Chrome (2K) other languages: $| or FileHandle autoflush (Perl), flush (Python), ios.flush (Ruby)

flushing and domain blocking you might need to move flushed resources to a domain different from the HTML doc blocked by HTML document html image script html image script different domains case study: Google search google image script 204

questions What does it mean to "flush" the document? Why does this help performance? Where should I put the call to flush() in my backend code? Will flushing work behind my company proxy?

Using Iframes Sparingly load 100 empty elements of each type iframes are 10-100x more expensive 1IE 6, 7, 8; FF 2, 3.0, 3.1b2; Safari 3.2, 4; Opera 9.63, 10; Chrome 1.0, 2.0

iframes block onload parent's onload doesn't fire until iframe and all its components are downloaded workaround for Safari and Chrome: set iframe src in JavaScript <iframe id=iframe1 src=""></iframe> <script type="text/javascript"> document.getElementById('iframe1').src="url"; </script>

scripts block iframe IE script Firefox script Safari Chrome Opera script no surprise – scripts in the parent block the iframe from loading

stylesheets block iframe (IE, FF) Firefox stylesheet Safari Chrome Opera stylesheet surprise – stylesheets in the parent block the iframe or its resources in IE & Firefox

stylesheets after iframe still block (FF) IE stylesheet Firefox stylesheet Safari Chrome Opera stylesheet surprise – even moving the stylesheet after the iframe still causes the iframe's resources to be blocked in Firefox

iframes: no free connections parent iframe iframe shares connection pool with parent (here – 2 connections per server in IE 7)

questions Why are iframes the most expensive DOM element? Why is the fact that iframes block the onload event bad?

Simplifying CSS Selectors rule selector #toc > LI { font-weight: bold; } combinator simple selectors declaration block http://stevesouders.com/efws/selectors.php

types of CSS selectors ID selectors class selectors type selectors #toc { margin-left: 20px; } element whose ID attribute has the value "toc" class selectors .chapter { font-weight: bold; } elements with class=chapter type selectors A { text-decoration: none; } all A elements in the document tree http://www.w3.org/TR/CSS2/selector.html

types of CSS selectors adjacent sibling selectors child selectors H1 + #toc { margin-top: 40px; } an element with ID=toc that immediately follows an H1 child selectors #toc > LI { font-weight: bold; } all LI elements whose parent has id="toc" descendant selectors #toc A { color: #444; } all A elements that have id="toc" as an ancestor

types of CSS selectors universal selectors attribute selectors * { font-family: Arial; } all elements where the "hidden" attribute is "true" attribute selectors [href="#index"] { font-style: italic; } all elements where the href attribute is "#index" psuedo classes and elements A:hover { text-decoration: underline; } non-DOM behavior others: :visited, :link, :active, :focus, :first-child, :before, :after

writing efficient CSS https://developer.mozilla.org/en/Writing_Efficient_CSS "The style system matches a rule by starting with the rightmost selector and moving to the left through the rule's selectors. As long as your little subtree continues to check out, the style system will continue moving to the left until it either matches the rule or bails out because of a mismatch." #toc > LI { font-weight: bold; } find every LI whose parent is id="toc" #toc A { color: #444; } find every A and climb its ancestors until id="toc" or DOM root (!) is found

writing efficient CSS avoid universal selectors don't qualify ID selectors bad: DIV #navbar {} good: #navbar {} don't qualify class selectors bad: LI .tight {} good: .li-tight {} make rules as specific as possible bad: #navbar A {} good: .a-navbar {} https://developer.mozilla.org/en/Writing_Efficient_CSS

writing efficient CSS avoid descendant selectors bad: UL LI A {} better: UL > LI > A {} avoid tag-child selectors bad: UL > LI > A {} best: .li-anchor {} be wary of child selectors rely on inheritance http://www.w3.org/TR/CSS21/propidx.html https://developer.mozilla.org/en/Writing_Efficient_CSS by David Hyatt 4/21/2000

Testing CSS Performance 20K TD elements http://jon.sykes.me/152/testing-css-performance-pt-2

testing massive CSS 20K DIV > P > A elements no style: control tag: A {} class: .a00001 {} .a20000 {} descender: DIV DIV DIV P A.a00001 {} child: DIV > DIV > DIV > P > A.a00001 {} http://jon.sykes.me/153/more-css-performance-testing-pt-3 3 revisions

CSS performance isn't linear IE 7 "cliff" at 18K rules

real world levels of CSS # Rules # elements Avg Depth AOL 2289 1628 13 eBay 305 588 14 Facebook 2882 1966 17 Google Search 92 552 8 Live Search 376 449 12 MSN.com 1038 886 11 MySpace 932 444 9 Wikipedia 795 1333 10 Yahoo! 800 564 YouTube 821 817 average 1033 923

testing typical CSS 1K rules (vs. 20K) same amount of CSS in all test pages 30 ms avg delta "costly"selectors aren't always costly (at typical levels) are these selectors "costly"? DIV DIV DIV P A.class0007 { ... } http://www.stevesouders.com/blog/2009/03/10/performance-impact-of-css-selectors/

testing expensive selectors 1K rules (vs. 20K) same amount of CSS in all test pages 2126 ms avg delta! truly expensive selector A.class0007 * { ... } compare to: DIV DIV DIV P A.class0007 { ... } the key is the key selector – the rightmost argument

CSS3 selectors (bad) more David Hyatt: "The sad truth about CSS3 selectors is that they really shouldn’t be used at all if you care about page performance. Decorating your markup with classes and ids and matching purely on those while avoiding all uses of sibling, descendant and child selectors will actually make a page perform significantly better in all browsers." http://shauninman.com/archive/2008/05/05/css_qualified_selec tors#comment_3942

selectors to avoid A.class0007 DIV { ... } #id0007 > A { ... } .class0007 [href] { ... } DIV:first-child { ... } http://stevesouders.com/efws/css-selectors/csscreate.php?sel=DIV%3Afirst-child

reflow time vs. load time reflow – time to apply CSS, re-layout elements, and repaint triggered by DHTML: elem.className = "newclass"; elem.style.cssText = "color: red"; elem.style.padding = "8px"; elem.style.display = ""; reflow can happen multiple times for long- lasting Web 2.0 apps

reflow time by browser DHTML action Chr1 Chr2 FF2 FF3 IE6,7 IE 8 Op Saf3 Saf4 className 1x display none - display default 2x visibility hidden visibility visible padding 4x width length width percent width default background font-size reflow performance varies by browser and action "1x" ranges from 1-6 seconds depending on browser

Simplifying CSS Selectors efficient CSS comes at a cost – page weight focus optimization on selectors where the key selector matches many elements reduce the number of selectors

questions What's the surprise in how selectors are applied? What's the part of the selector is the key to focus on for performance? Why do some of the selector optimizations increase page weight? Why is reflow time important today?

morning wrap-up EFWS 1-4 break EFWS 5-8 performance analysis state of performance

morning wrap-up EFWS 1-4 break EFWS 5-8 performance analysis state of performance

state of performance 2008 2009 year of the browser visibility into the browser web devs think "Web 2.0" speed as a feature performance standards JavaScript help performance off the desktop fast-by-default

visibility into the browser hard to measure the exact things we're trying to optimize HTML parsing CSS parsing JS parsing and execution (as the page loads) DOM manipulation

web page profiler (concept) paint events memory CPU JavaScript CSS

web devs think "Web 2.0" the days of Web 1.0 are fading away... but web developers still think in terms of the page reloading on every user action Web 2.0 pages may persist for hours need to evolve the way we program to keep our eyes on the long run, for example: vigilant about memory leaks # of DOM elements optimize JS and CSS for ongoing DHTML

speed as a feature sites use speed as a competitive advantage remember Yahoo! and Google search? Facebook vulnerability? aggregators & vendors prioritize based on speed Google incorporates load time into Adwords Quality Score http://adwords.blogspot.com/2008/03/landing-page-load-time-will-soon-be.html

performance standards test suites for web sites benchmarks for browsers standards for "response time" web page digest archive of all relevant information about a page load shared instrumentation and reporting

JavaScript help tools to automatically split (huge) Web 2.0 JavaScript payload into smaller initial module and larger later module(s) a la Doloto http://research.microsoft.com/research/pubs/view.aspx?tr_id=1402 ability to specify Opera-like defer using HTML <script defer src=...> <script afteronload src=...>

focus on other platforms proliferation of web clients besides desktop browsers... requires investigation and evangelism of performance best practices for these platforms mobile, PDA auto, mass transit airplane 3rd world

fast by default I enjoy hard work... ...but we shouldn't have to spend this much time solving the same problem again and again Runtime Page Optimizer http://www.getrpo.com/ Strangeloop http://www.strangeloopnetworks.com/ combine these with smush.it

prefetch services ensure resources are cached for sites I always visit browser support user-specified and auto-detected "favorite sites" two caches: transient and persistent persistent cache isn't purged or flushed by default clientside support e.g., Gears prefetch standard protocol /prefetch.xml – manifest list

user-driven transparency Internet community contributes to performance data warehouse examples: UA Profiler – http://stevesouders.com/ua/ PBWiki JavaScript Library loading speed Cloud Four Mobile Connection Test

takeaways focus on the frontend run YSlow: http://developer.yahoo.com/yslow this year's focus: JavaScript speed matters 72 years = 2,270,592,000 seconds = 500ms * 4.4B page views

impact on revenue +500 ms  -20% traffic1 Google: Yahoo: Amazon: +500 ms  -20% traffic1 +400 ms  -5-9% full-page traffic2 +100 ms  -1% sales1 72 years = 2,270,592,000 seconds = 500ms * 4.4B page views 1 http://home.blarg.net/~glinden/StanfordDataMining.2006-11-29.ppt 2 http://www.slideshare.net/stoyan/yslow-20-presentation

cost savings hardware – reduced load bandwidth – reduced response size 72 years = 2,270,592,000 seconds = 500ms * 4.4B page views http://billwscott.com/share/presentations/2008/stanford/HPWP-RealWorld.pdf

Even Faster Web Sites if you want better user experience more revenue reduced operating expenses the strategy is clear Even Faster Web Sites 72 years = 2,270,592,000 seconds = 500ms * 4.4B page views

"thank you" by nj dodge: http://flickr.com/photos/nj_dodge/187190601/ Steve Souders souders@google.com http://stevesouders.com/docs/oreilly-master-class-part2.ppt