HOW EDMUNDS GOT IN THE FAST LANE    80% Reduction in Page Load Time in   Simple Steps                                    ...
The Results  onLoad: 8.4s ➙ 1.9s      (≈ 80% reduction)  Page Views: 20%  Bounce Rate: 4%  Ad Impression Variance: 3%Sunda...
Edmunds, Inc.               Online since 1995                Properties:                200M+ page views/month            ...
Memory LaneSunday, January 16, 2011
Edmunds.com Legacy SiteSunday, January 16, 2011
Meanwhile ...                                                   “95% of Performance                                       ...
The Real Picture!Sunday, January 16, 2011
Site Condition                           - Too Many Requests (150+)                           - Many Blocking Requests (20...
We Started Tinkering ...Sunday, January 16, 2011
Quick Wins: CACHING!      - Solution              Added Expires Header + Removed Etags      - Result:              34% red...
... but Legacy was complicated.Sunday, January 16, 2011
2008: A Vision Was BornSunday, January 16, 2011
Redesign Objectives                           PERFORMANCE                           (Faster Page Loads .. onLoad =< 1.5s) ...
The Mindset                                FASTER PAGES                           POSITIVE USER EXPERIENCE                ...
The Challenge                 HTTP Requests                Page Performance                                    User       ...
Types of HTTP Requests                             1) Our Own Requests                               (files served from our...
3rd-party      Requests                                  Exist in Two Forms                           JavaScript          ...
3rd-party   Requests                               Roles on Our Sites                             JavaScript              ...
Our Challenge           3rd-party Requests             HTTP Requests              Page Performance                        ...
3rd-party          iFrame   3rd-party   JavaScript                       Agreeable         ProblematicSunday, January 16, ...
Mission: Control 3rd                Attempt #1:                Override document.write()function                Example:  ...
Mission: Control 3rd               Attempt #2:               Load in iFrame and Copy on Load (iFrame’n’Copy)              ...
Our New Found Creed        You Can Not Control EverythingSunday, January 16, 2011
Edmunds vs.             3rd-party           Requests                                                                  %"#$...
Our New Found Creed        Make What You Control FASTSunday, January 16, 2011
JavaScript LoaderSunday, January 16, 2011
How Does it Work?Sunday, January 16, 2011
How Does it Work?  ❶        Quick page is  served to userSunday, January 16, 2011
How Does it Work?                                      2       1  ❶        Quick page is                                  ...
How Does it Work?                                      2       1  ❶        Quick page is                                  ...
Component 1                                                                  Component 2                Component 3  Regis...
Component 1                                                                  Component 2                Component 3  Regis...
Component 1                                                                  Component 2                Component 3  Regis...
Component 1                                                                  Component 2                Component 3  Regis...
Registration                                                                                                      Process ...
Process  function load() {      // .....      // .....                                                        Dependencies...
Get a reference to                                  the function                             Process  function load() {   ...
Get a reference to                                  the function                             Process  function load() {   ...
Get a reference to                                 the function                          Process  function load() {      /...
Get a reference to                                 the function                          Process  function load() {      /...
Get a reference to                                 the function                          Process  function load() {      /...
Rendering Components                           execControls: function(start) {                                // Get a tim...
Rendering Components                           execControls: function(start) {                                // Get a tim...
Rendering Components                           execControls: function(start) {                                // Get a tim...
Rendering Components                           execControls: function(start) {                                // Get a tim...
Our New Found Creed        Treat Everything Else as a Black BoxSunday, January 16, 2011
3rd-party          iFrame   3rd-party   JavaScript                       Agreeable         ProblematicSunday, January 16, ...
3rd-party          iFrame   3rd-party   JavaScript                       Agreeable         ProblematicSunday, January 16, ...
3rd-party                 Handling Logic                                                    Component                    P...
Rendering           3rd-party              JavaScript:                                                                    ...
Rendering          3rd-party              JavaScript:                                                                    P...
Rendering          3rd-party            JavaScript:                                                                    Par...
Rendering        3rd-party           JavaScript:                                                                  Part 1 -...
Rendering        3rd-party           JavaScript:                                                                  Part 1 -...
Rendering              3rd-party           JavaScript:                                                    Part 2 - Render ...
Rendering              3rd-party           JavaScript:                                                    Part 2 - Render ...
Rendering              3rd-party           JavaScript:                                                    Part 2 - Render ...
Rendering              3rd-party           JavaScript:                                                    Part 2 - Render ...
Rendering              3rd-party           JavaScript:                                                    Part 2 - Render ...
In Summary        You Can Not Control Everything                   It’s OK, it really is :-)        Make What You Contro...
Inside Line ResultsSunday, January 16, 2011
Inside Line Redesign Objectives                           PERFORMANCE                           (onLoad ≈1.5)             ...
Another Vision Was BornSunday, January 16, 2011
Legacy   RedesignSunday, January 16, 2011
Edmunds Legacy                Edmunds Redesign                     8.4 seconds          1.9 seconds                       ...
The Results                           20%                           Total Page Views Per SessionSunday, January 16, 2011
The Results                           3%                           Ad Impression VarianceSunday, January 16, 2011
The Results                           4%                           Bounce RateSunday, January 16, 2011
In The Works ...Sunday, January 16, 2011
JavaScript Loader 2.0                           EVEN FASTER!                           Load in parallel and execute on-dem...
Soon ...                           http://www.github.com/edmundsSunday, January 16, 2011
What About The Future?Sunday, January 16, 2011
 You Can Not Control Everything       Make What You Control FAST       Treat Everything Else as a Black Box            ...
Edmunds MobileSunday, January 16, 2011
Edmunds PlatformSunday, January 16, 2011
Edmunds Platform           Plug-n-Play                             Widgets                                                ...
Edmunds Platform                           3rd-party Consumer                                       ®                     ...
Let’s Continue the Conversation                                                                     @codeish   http://tech...
Upcoming SlideShare
Loading in...5
×

How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps

169,648

Published on

(YouTube presentation is at the end of the slides)

Back in the day, the onLoad event on our edmunds.com and insidelien.com pages used to take 9 seconds to fire! Yeah, we thought it was awful too. That's why in late 2008, we set out to do something about. In this deck, I will discuss the three main concepts that helped us take our pages from slow to really fast.

Published in: Technology
4 Comments
22 Likes
Statistics
Notes
No Downloads
Views
Total Views
169,648
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
203
Comments
4
Likes
22
Embeds 0
No embeds

No notes for slide

How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps

  1. 1. HOW EDMUNDS GOT IN THE FAST LANE 80% Reduction in Page Load Time in Simple Steps by Ismail ElshareefSunday, January 16, 2011
  2. 2. The Results onLoad: 8.4s ➙ 1.9s (≈ 80% reduction) Page Views: 20% Bounce Rate: 4% Ad Impression Variance: 3%Sunday, January 16, 2011
  3. 3. Edmunds, Inc. Online since 1995 Properties: 200M+ page views/month Revenue = Ads + LeadsSunday, January 16, 2011
  4. 4. Memory LaneSunday, January 16, 2011
  5. 5. Edmunds.com Legacy SiteSunday, January 16, 2011
  6. 6. Meanwhile ... “95% of Performance is Frontend” - Steve Souders “Performance Matters!” - Organizations +100ms in response time ➡ -1% in sales -30% in file size ➡ +30% in requestsSunday, January 16, 2011
  7. 7. The Real Picture!Sunday, January 16, 2011
  8. 8. Site Condition - Too Many Requests (150+) - Many Blocking Requests (20+) - Perceived Slowness (onLoad in 8.4s) - No Caching - 1 Domains Serves All Requests - External Factors (ads, videos, ..etc) - Dependency on DOM EventsSunday, January 16, 2011
  9. 9. We Started Tinkering ...Sunday, January 16, 2011
  10. 10. Quick Wins: CACHING! - Solution Added Expires Header + Removed Etags - Result: 34% reduction in bandwidth = 34TB annual savings = FREE video streaming for 2 years = Faster pages when cache is primedSunday, January 16, 2011
  11. 11. ... but Legacy was complicated.Sunday, January 16, 2011
  12. 12. 2008: A Vision Was BornSunday, January 16, 2011
  13. 13. Redesign Objectives PERFORMANCE (Faster Page Loads .. onLoad =< 1.5s) RICHER CONTENT (Flash, video, slicker UXD, ...etc) BETTER REVENUE (Positive impact on ad impressions)Sunday, January 16, 2011
  14. 14. The Mindset FASTER PAGES POSITIVE USER EXPERIENCE HIGHER REVENUESunday, January 16, 2011
  15. 15. The Challenge HTTP Requests Page Performance User ExperienceSunday, January 16, 2011
  16. 16. Types of HTTP Requests 1) Our Own Requests (files served from our own domains) 2) 3rd-party Requests (files served from other domains)Sunday, January 16, 2011
  17. 17. 3rd-party Requests Exist in Two Forms JavaScript iFrame Cons: Cons: - Access to DOM - Fixed width/height - document.write Pros: Pros: - Easy to lazy-load - Richer Content - Sandboxed CodeSunday, January 16, 2011
  18. 18. 3rd-party Requests Roles on Our Sites JavaScript iFrame Analytics A/B Testing Ads Video Widgets Monitoring SurveysSunday, January 16, 2011
  19. 19. Our Challenge 3rd-party Requests HTTP Requests Page Performance User ExperienceSunday, January 16, 2011
  20. 20. 3rd-party iFrame 3rd-party JavaScript Agreeable ProblematicSunday, January 16, 2011
  21. 21. Mission: Control 3rd Attempt #1: Override document.write()function Example: var buffer = []; document.write = function(st) { buffer.push(st); } // when a specific event occurs ... var s = buffer.join(‘’); document.getElementById(‘destination’).innerHTML = s; Problem: Didn’t work with daisy-chained document.write callsSunday, January 16, 2011
  22. 22. Mission: Control 3rd Attempt #2: Load in iFrame and Copy on Load (iFrame’n’Copy) Example: var jsAd = “http://ad.doubleclick.net/adj/....”; iFrameObj.src = “http://www.edmunds.com/adSub.html?”+jsAd; // Option 1: listen to iFrame onLoad event // Option 2: iFrame page calls parent when done Problem: Buggy in IE 7 + Hard to MaintainSunday, January 16, 2011
  23. 23. Our New Found Creed  You Can Not Control EverythingSunday, January 16, 2011
  24. 24. Edmunds vs. 3rd-party Requests %"#$ %"#$ &()*+,$-./).+0+$ 12345206$-./).+0+$ !"#$ !"#$ New Sites Old Sites &()*+,$-./).+0+$ 12345206$-./).+0+$Sunday, January 16, 2011
  25. 25. Our New Found Creed  Make What You Control FASTSunday, January 16, 2011
  26. 26. JavaScript LoaderSunday, January 16, 2011
  27. 27. How Does it Work?Sunday, January 16, 2011
  28. 28. How Does it Work? ❶ Quick page is served to userSunday, January 16, 2011
  29. 29. How Does it Work? 2 1 ❶ Quick page is 3 served to user 4 ❷ Page components register themselves with the page 5 6 7Sunday, January 16, 2011
  30. 30. How Does it Work? 2 1 ❶ Quick page is 3 served to user 4 ❷ Page components register themselves with the page 5 ❸ Registered components rendered 6 in parallel 7Sunday, January 16, 2011
  31. 31. Component 1 Component 2 Component 3 Registration Component 4 Component 5 Process Component 6 I need YUI’s Carousel module. Here’s my code, render me right away! I need flash.js and here’s my code. I need to be rendered right away Component 7 I need YUI’s Carousel module and here’s my code. I am below the fold so I can wait Component 8Sunday, January 16, 2011
  32. 32. Component 1 Component 2 Component 3 Registration Component 4 Component 5 Process Declare Dependencies Component 6 I need YUI’s Carousel module. Here’s my code, render me right away! I need flash.js and here’s my code. I need to be rendered right away Component 7 I need YUI’s Carousel module and here’s my code. I am below the fold so I can wait Component 8Sunday, January 16, 2011
  33. 33. Component 1 Component 2 Component 3 Registration Component 4 Component 5 Process Declare Dependencies Component 6 I need YUI’s Carousel module. Here’s my code, render me right away! Submit Functionality I need flash.js and here’s my code. I need to be rendered right away Component 7 I need YUI’s Carousel module and here’s my code. I am below the fold so I can wait Component 8Sunday, January 16, 2011
  34. 34. Component 1 Component 2 Component 3 Registration Component 4 Component 5 Process Declare Dependencies Component 6 I need YUI’s Carousel module. Here’s my code, render me right away! Submit Functionality I need flash.js and here’s my code. I need to be rendered right away Component 7 Set Priority I need YUI’s Carousel module and here’s my code. I am below the fold so I can wait Component 8Sunday, January 16, 2011
  35. 35. Registration Process Declare Dependencies PAGESETUP.files.push(file1.js); PAGESETUP.files.push(file2.js); PAGESETUP.files.push(file7.js); Submit functionality PAGESETUP.addControl(function() { // .... // Anything from rendering a component to making an AJAX call. All goes here. // ... }, high); Set PrioritySunday, January 16, 2011
  36. 36. Process function load() { // ..... // ..... Dependencies var parent = arguments.callee; if (unique_files.length) { var file = unique_files.shift(); var js = document.createElement(script); js.type = text/javascript; js.src = file; if (!FF || FF >= 2) { js.onreadystatechange = function() { if (this.readyState == complete || this.readyState == loaded || this.status == 304 || this.status == 404) { parent(); } }; } else { parent(); } document.getElementsByTagName(head)[0].appendChild(js); if (PAGESETUP.execControls) { PAGESETUP.execControls(); } } }Sunday, January 16, 2011
  37. 37. Get a reference to the function Process function load() { // ..... // ..... Dependencies var parent = arguments.callee; if (unique_files.length) { var file = unique_files.shift(); var js = document.createElement(script); js.type = text/javascript; js.src = file; if (!FF || FF >= 2) { js.onreadystatechange = function() { if (this.readyState == complete || this.readyState == loaded || this.status == 304 || this.status == 404) { parent(); } }; } else { parent(); } document.getElementsByTagName(head)[0].appendChild(js); if (PAGESETUP.execControls) { PAGESETUP.execControls(); } } }Sunday, January 16, 2011
  38. 38. Get a reference to the function Process function load() { // ..... // ..... Dependencies var parent = arguments.callee; if (unique_files.length) { var file = unique_files.shift(); var js = document.createElement(script); Process unique js.type = text/javascript; js.src = file; dependencies if (!FF || FF >= 2) { js.onreadystatechange = function() { if (this.readyState == complete || this.readyState == loaded || this.status == 304 || this.status == 404) { parent(); } }; } else { parent(); } document.getElementsByTagName(head)[0].appendChild(js); if (PAGESETUP.execControls) { PAGESETUP.execControls(); } } }Sunday, January 16, 2011
  39. 39. Get a reference to the function Process function load() { // ..... // ..... Dependencies var parent = arguments.callee; if (unique_files.length) { var file = unique_files.shift(); var js = document.createElement(script); Process unique js.type = text/javascript; js.src = file; dependencies if (!FF || FF >= 2) { js.onreadystatechange = function() { if (this.readyState == complete || For all browsers but this.readyState == loaded || FireFox < 4, Download this.status == 304 || this.status == 404) dependencies serially ... { parent(); } }; } else { parent(); } document.getElementsByTagName(head)[0].appendChild(js); if (PAGESETUP.execControls) { PAGESETUP.execControls(); } } }Sunday, January 16, 2011
  40. 40. Get a reference to the function Process function load() { // ..... // ..... Dependencies var parent = arguments.callee; if (unique_files.length) { var file = unique_files.shift(); var js = document.createElement(script); Process unique js.type = text/javascript; js.src = file; dependencies if (!FF || FF >= 2) { js.onreadystatechange = function() { if (this.readyState == complete || For all browsers but this.readyState == loaded || FireFox < 4, Download this.status == 304 || this.status == 404) dependencies serially ... { parent(); } }; Otherwise, download in } else { parallel parent(); } document.getElementsByTagName(head)[0].appendChild(js); if (PAGESETUP.execControls) { PAGESETUP.execControls(); } } }Sunday, January 16, 2011
  41. 41. Get a reference to the function Process function load() { // ..... // ..... Dependencies var parent = arguments.callee; if (unique_files.length) { var file = unique_files.shift(); var js = document.createElement(script); Process unique js.type = text/javascript; js.src = file; dependencies if (!FF || FF >= 2) { js.onreadystatechange = function() { if (this.readyState == complete || For all browsers but this.readyState == loaded || FireFox < 4, Download this.status == 304 || this.status == 404) dependencies serially ... { parent(); } }; Otherwise, download in } else { parallel parent(); } document.getElementsByTagName(head)[0].appendChild(js); if (PAGESETUP.execControls) { PAGESETUP.execControls(); } } When done downloading, } render registered components!Sunday, January 16, 2011
  42. 42. Rendering Components execControls: function(start) { // Get a timestamp here to indicate the start of the process // Merge all the queues into one! high->normal->low var merged = this.merged; // Go through the merged array and execute the chunks! setTimeout(function() { // Get a chunk from the top of the array var item = merged.shift(); if(item){ // Execute the chunk! item.call(); } if (merged.length > 0) { // Wait 25 ms and then get the next chunk setTimeout(arguments.callee, 25); } else { // Otherwise, get a timestamp to indicate the end of the process } }, 0); },Sunday, January 16, 2011
  43. 43. Rendering Components execControls: function(start) { // Get a timestamp here to indicate the start of the process // Merge all the queues into one! high->normal->low var merged = this.merged; // Go through the merged array and execute the chunks! setTimeout(function() { // Get a chunk from the top of the array Combine functions var item = merged.shift(); submitted by if(item){ components in // Execute the chunk! item.call(); priority order (high } -> normal -> low) if (merged.length > 0) { // Wait 25 ms and then get the next chunk setTimeout(arguments.callee, 25); } else { // Otherwise, get a timestamp to indicate the end of the process } }, 0); },Sunday, January 16, 2011
  44. 44. Rendering Components execControls: function(start) { // Get a timestamp here to indicate the start of the process // Merge all the queues into one! high->normal->low var merged = this.merged; // Go through the merged array and execute the chunks! setTimeout(function() { // Get a chunk from the top of the array Combine functions var item = merged.shift(); submitted by if(item){ components in // Execute the chunk! Process one function at item.call(); a time ... priority order (high } -> normal -> low) if (merged.length > 0) { // Wait 25 ms and then get the next chunk setTimeout(arguments.callee, 25); } else { // Otherwise, get a timestamp to indicate the end of the process } }, 0); },Sunday, January 16, 2011
  45. 45. Rendering Components execControls: function(start) { // Get a timestamp here to indicate the start of the process // Merge all the queues into one! high->normal->low var merged = this.merged; // Go through the merged array and execute the chunks! setTimeout(function() { // Get a chunk from the top of the array Combine functions var item = merged.shift(); submitted by if(item){ components in // Execute the chunk! Process one function at item.call(); a time ... priority order (high } -> normal -> low) if (merged.length > 0) { // Wait 25 ms and then get the next chunk setTimeout(arguments.callee, 25); } else { // Otherwise, get a timestamp to indicate the end of the process } every 25 ms! }, 0); },Sunday, January 16, 2011
  46. 46. Our New Found Creed  Treat Everything Else as a Black BoxSunday, January 16, 2011
  47. 47. 3rd-party iFrame 3rd-party JavaScript Agreeable ProblematicSunday, January 16, 2011
  48. 48. 3rd-party iFrame 3rd-party JavaScript Agreeable ProblematicSunday, January 16, 2011
  49. 49. 3rd-party Handling Logic Component Placeholder Markup on a page YES NO 3rd-party? Process through JS Loader JavaScript iFrame Render before </html> in a Register as "3rd- Remove original call hidden <div> party" component Relocate generated markup into placeholderSunday, January 16, 2011
  50. 50. Rendering 3rd-party JavaScript: Part 1 - Register the Call // Add the placeholder <div id="js-ad1"></div> <script type="text/javascript"> (function() { // Construct the ad URL var ad = new EDMUNDS.AdUnit(); // Inform the PAGESETUP object of what’s going on PAGESETUP.thirdpartyids.push(js-ad1); PAGESETUP.thirdpartydetails[js-ad1] = {}; PAGESETUP.thirdpartydetails[js-ad1][type] = ad; PAGESETUP.thirdpartydetails[js-ad1][src] = ad.getAdUrl(); })(); </script>Sunday, January 16, 2011
  51. 51. Rendering 3rd-party JavaScript: Part 1 - Register the Call Placeholder Markup // Add the placeholder <div id="js-ad1"></div> <script type="text/javascript"> (function() { // Construct the ad URL var ad = new EDMUNDS.AdUnit(); // Inform the PAGESETUP object of what’s going on PAGESETUP.thirdpartyids.push(js-ad1); PAGESETUP.thirdpartydetails[js-ad1] = {}; PAGESETUP.thirdpartydetails[js-ad1][type] = ad; PAGESETUP.thirdpartydetails[js-ad1][src] = ad.getAdUrl(); })(); </script>Sunday, January 16, 2011
  52. 52. Rendering 3rd-party JavaScript: Part 1 - Register the Call Placeholder Markup // Add the placeholder <div id="js-ad1"></div> Register details about <script type="text/javascript"> the JavaScript Request (function() { // Construct the ad URL var ad = new EDMUNDS.AdUnit(); // Inform the PAGESETUP object of what’s going on PAGESETUP.thirdpartyids.push(js-ad1); PAGESETUP.thirdpartydetails[js-ad1] = {}; PAGESETUP.thirdpartydetails[js-ad1][type] = ad; PAGESETUP.thirdpartydetails[js-ad1][src] = ad.getAdUrl(); })(); </script>Sunday, January 16, 2011
  53. 53. Rendering 3rd-party JavaScript: Part 1 - Register the Call Placeholder Markup // Add the placeholder <div id="js-ad1"></div> Register details about <script type="text/javascript"> the JavaScript Request (function() { // Construct the ad URL var ad = new EDMUNDS.AdUnit(); // Inform the PAGESETUP object of what’s going on Register: placeholder ID PAGESETUP.thirdpartyids.push(js-ad1); PAGESETUP.thirdpartydetails[js-ad1] = {}; PAGESETUP.thirdpartydetails[js-ad1][type] = ad; PAGESETUP.thirdpartydetails[js-ad1][src] = ad.getAdUrl(); })(); </script>Sunday, January 16, 2011
  54. 54. Rendering 3rd-party JavaScript: Part 1 - Register the Call Placeholder Markup // Add the placeholder <div id="js-ad1"></div> Register details about <script type="text/javascript"> the JavaScript Request (function() { // Construct the ad URL var ad = new EDMUNDS.AdUnit(); // Inform the PAGESETUP object of what’s going on Register: placeholder ID PAGESETUP.thirdpartyids.push(js-ad1); PAGESETUP.thirdpartydetails[js-ad1] = {}; PAGESETUP.thirdpartydetails[js-ad1][type] = ad; PAGESETUP.thirdpartydetails[js-ad1][src] = ad.getAdUrl(); })(); </script> Register: JavaScript CallSunday, January 16, 2011
  55. 55. Rendering 3rd-party JavaScript: Part 2 - Render at the bottom of the page <script type="text/javascript"> if (PAGESETUP.thirdpartyids.length > 0) { (function() { var id = PAGESETUP.thirdpartyids.shift(); var file = PAGESETUP.thirdpartydetails[id].src; if (file) { document.write(<div id="+id+-cache+" style="display:none;"> <div id="+id+-root+">); document.write(<script type="text/javascript" src="+file+" ></script>); } })(); } </script> <script type="text/javascript">document.write(</div></div>);</script>Sunday, January 16, 2011
  56. 56. Rendering 3rd-party JavaScript: Part 2 - Render at the bottom of the page Get the registered ID <script type="text/javascript"> if (PAGESETUP.thirdpartyids.length > 0) { (function() { var id = PAGESETUP.thirdpartyids.shift(); var file = PAGESETUP.thirdpartydetails[id].src; if (file) { document.write(<div id="+id+-cache+" style="display:none;"> <div id="+id+-root+">); document.write(<script type="text/javascript" src="+file+" ></script>); } })(); } </script> <script type="text/javascript">document.write(</div></div>);</script>Sunday, January 16, 2011
  57. 57. Rendering 3rd-party JavaScript: Part 2 - Render at the bottom of the page Get the registered ID <script type="text/javascript"> Get the registered if (PAGESETUP.thirdpartyids.length > 0) { (function() { JavaScript Call var id = PAGESETUP.thirdpartyids.shift(); var file = PAGESETUP.thirdpartydetails[id].src; if (file) { document.write(<div id="+id+-cache+" style="display:none;"> <div id="+id+-root+">); document.write(<script type="text/javascript" src="+file+" ></script>); } })(); } </script> <script type="text/javascript">document.write(</div></div>);</script>Sunday, January 16, 2011
  58. 58. Rendering 3rd-party JavaScript: Part 2 - Render at the bottom of the page Get the registered ID <script type="text/javascript"> Get the registered if (PAGESETUP.thirdpartyids.length > 0) { (function() { JavaScript Call var id = PAGESETUP.thirdpartyids.shift(); var file = PAGESETUP.thirdpartydetails[id].src; if (file) { document.write(<div id="+id+-cache+" style="display:none;"> <div id="+id+-root+">); document.write(<script type="text/javascript" src="+file+" ></script>); } })(); Wrap the call in a } </script> hidden DIV <script type="text/javascript">document.write(</div></div>);</script>Sunday, January 16, 2011
  59. 59. Rendering 3rd-party JavaScript: Part 2 - Render at the bottom of the page Get the registered ID <script type="text/javascript"> Get the registered if (PAGESETUP.thirdpartyids.length > 0) { (function() { JavaScript Call var id = PAGESETUP.thirdpartyids.shift(); var file = PAGESETUP.thirdpartydetails[id].src; if (file) { document.write(<div id="+id+-cache+" style="display:none;"> <div id="+id+-root+">); document.write(<script type="text/javascript" src="+file+" ></script>); } })(); Wrap the call in a } </script> hidden DIV <script type="text/javascript">document.write(</div></div>);</script> Close the DIVSunday, January 16, 2011
  60. 60. In Summary  You Can Not Control Everything It’s OK, it really is :-)  Make What You Control FAST No DOM Event dependency Render components as soon as page is parsed Render components in priority  Treat Everything Else as a Black Box Process separately Delay inclusion as much as possible It’s about “mitigation” not “elimination”Sunday, January 16, 2011
  61. 61. Inside Line ResultsSunday, January 16, 2011
  62. 62. Inside Line Redesign Objectives PERFORMANCE (onLoad ≈1.5) RICHER CONTENT (Large Flash content serving photos and videos) BETTER REVENUE (Ad impression variance reduced by 3%)Sunday, January 16, 2011
  63. 63. Another Vision Was BornSunday, January 16, 2011
  64. 64. Legacy RedesignSunday, January 16, 2011
  65. 65. Edmunds Legacy Edmunds Redesign 8.4 seconds 1.9 seconds ≈ 80% Reduction in Load Time!Sunday, January 16, 2011
  66. 66. The Results 20% Total Page Views Per SessionSunday, January 16, 2011
  67. 67. The Results 3% Ad Impression VarianceSunday, January 16, 2011
  68. 68. The Results 4% Bounce RateSunday, January 16, 2011
  69. 69. In The Works ...Sunday, January 16, 2011
  70. 70. JavaScript Loader 2.0 EVEN FASTER! Load in parallel and execute on-demand COMPONENT METRICS (When it’s loaded, how long it took, ..etc) MANY ENHANCEMENTS :)Sunday, January 16, 2011
  71. 71. Soon ... http://www.github.com/edmundsSunday, January 16, 2011
  72. 72. What About The Future?Sunday, January 16, 2011
  73. 73.  You Can Not Control Everything  Make What You Control FAST  Treat Everything Else as a Black Box How Will It Apply To ...Sunday, January 16, 2011
  74. 74. Edmunds MobileSunday, January 16, 2011
  75. 75. Edmunds PlatformSunday, January 16, 2011
  76. 76. Edmunds Platform Plug-n-Play Widgets Syndication Managed Products raw data Content ® Standalone packaged data Tools Open Source Plugins Code Snippets Cars Mobile UI Handheld Wired UI API Backend SystemsSunday, January 16, 2011
  77. 77. Edmunds Platform 3rd-party Consumer ® 3rd-party ProviderSunday, January 16, 2011
  78. 78. Let’s Continue the Conversation @codeish http://tech.edmunds.comPhoto Credits:All Car Photos are from www.insideline.comhttp://www.cantronicsglobal.com/images/MissionVision.jpghttp://www.kewlwallpapers.com/images/wallpapers/John_C-680196.jpegSunday, January 16, 2011

×