Your SlideShare is downloading. ×
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
How Edmunds Got in the Fast Lane: 80% Reduction in Page Load Time in 3 Simple Steps
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

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

159,862

Published on

(YouTube presentation is at the end of the slides) …

(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
21 Likes
Statistics
Notes
No Downloads
Views
Total Views
159,862
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
203
Comments
4
Likes
21
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. HOW EDMUNDS GOT IN THE FAST LANE 80% Reduction in Page Load Time in Simple Steps by Ismail ElshareefSunday, January 16, 2011
  • 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. Edmunds, Inc. Online since 1995 Properties: 200M+ page views/month Revenue = Ads + LeadsSunday, January 16, 2011
  • 4. Memory LaneSunday, January 16, 2011
  • 5. Edmunds.com Legacy SiteSunday, January 16, 2011
  • 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. The Real Picture!Sunday, January 16, 2011
  • 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. We Started Tinkering ...Sunday, January 16, 2011
  • 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. ... but Legacy was complicated.Sunday, January 16, 2011
  • 12. 2008: A Vision Was BornSunday, January 16, 2011
  • 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. The Mindset FASTER PAGES POSITIVE USER EXPERIENCE HIGHER REVENUESunday, January 16, 2011
  • 15. The Challenge HTTP Requests Page Performance User ExperienceSunday, January 16, 2011
  • 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. 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. 3rd-party Requests Roles on Our Sites JavaScript iFrame Analytics A/B Testing Ads Video Widgets Monitoring SurveysSunday, January 16, 2011
  • 19. Our Challenge 3rd-party Requests HTTP Requests Page Performance User ExperienceSunday, January 16, 2011
  • 20. 3rd-party iFrame 3rd-party JavaScript Agreeable ProblematicSunday, January 16, 2011
  • 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. 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. Our New Found Creed  You Can Not Control EverythingSunday, January 16, 2011
  • 24. Edmunds vs. 3rd-party Requests %"#$ %"#$ &()*+,$-./).+0+$ 12345206$-./).+0+$ !"#$ !"#$ New Sites Old Sites &()*+,$-./).+0+$ 12345206$-./).+0+$Sunday, January 16, 2011
  • 25. Our New Found Creed  Make What You Control FASTSunday, January 16, 2011
  • 26. JavaScript LoaderSunday, January 16, 2011
  • 27. How Does it Work?Sunday, January 16, 2011
  • 28. How Does it Work? ❶ Quick page is served to userSunday, January 16, 2011
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Our New Found Creed  Treat Everything Else as a Black BoxSunday, January 16, 2011
  • 47. 3rd-party iFrame 3rd-party JavaScript Agreeable ProblematicSunday, January 16, 2011
  • 48. 3rd-party iFrame 3rd-party JavaScript Agreeable ProblematicSunday, January 16, 2011
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Inside Line ResultsSunday, January 16, 2011
  • 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. Another Vision Was BornSunday, January 16, 2011
  • 64. Legacy RedesignSunday, January 16, 2011
  • 65. Edmunds Legacy Edmunds Redesign 8.4 seconds 1.9 seconds ≈ 80% Reduction in Load Time!Sunday, January 16, 2011
  • 66. The Results 20% Total Page Views Per SessionSunday, January 16, 2011
  • 67. The Results 3% Ad Impression VarianceSunday, January 16, 2011
  • 68. The Results 4% Bounce RateSunday, January 16, 2011
  • 69. In The Works ...Sunday, January 16, 2011
  • 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. Soon ... http://www.github.com/edmundsSunday, January 16, 2011
  • 72. What About The Future?Sunday, January 16, 2011
  • 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. Edmunds MobileSunday, January 16, 2011
  • 75. Edmunds PlatformSunday, January 16, 2011
  • 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. Edmunds Platform 3rd-party Consumer ® 3rd-party ProviderSunday, January 16, 2011
  • 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

×