$30 off During Our Annual Pro Sale. View Details »

Pragmatic Performance with Third-Party JavaScript

Pragmatic Performance with Third-Party JavaScript

Presentation for Twitter at Open Web Camp 2012, in San Jose, CA. Covers a chunk of what we've learned over the years in building JavaScript for off-network usage, with aggressive performance optimisations.

Ben Ward

July 14, 2012

More Decks by Ben Ward

Other Decks in Programming


  1. Pragmatic Performance with 3rd Party JavaScript

  2. Ben Ward http://benward.me

  3. Ben Ward @benward

  4. None
  5. Tweet

  6. “3rd Party Javascript?!”, you exclaim.

  7. SlowBlockingBandwidthEatingRequestIncreasing…

  8. None
  9. Back right up. Why do these even exist?

  10. Back right up. How do they work?

  11. Widgets are products.

  12. Widgets are products for publishers.

  13. Widgets are products for developers.

  14. Widgets are products for people.

  15. Four stakeholders, delicately balanced.

  16. Provide features for mutual benefit.

  17. Share more of your links. Share more links.

  18. Easily quote Tweets. High quality Tweets.

  19. We take responsibility for technical costs.

  20. All stakeholders benefit from page performance.

  21. What’s in a page?

  22. None
  23. None
  24. The article itself.

  25. Publisher’s assets; images, scripts, analytics.

  26. Advertising. Publisher’s gotta eat.

  27. Other third parties sharing the page.

  28. Twitter for Websites; a suite of features.

  29. Tweet, follow, #hashtag and @mention buttons.

  30. Embeddable Tweets.

  31. Programmable JavaScript Events and Web Intents.

  32. Easy, as in fast to integrate.

  33. Fast, as in performant in the page.

  34. Performant, as in responsive to the environment.

  35. Responsive, as in embracing of the web.

  36. What expenses? Loading, rendering, bandwidth.

  37. DNS Look-up. HTTP(S) Request. Download. Parse/Execute. Render.

  38. DNS look-ups are a tax on every domain you use.

  39. Most of these visitors are not your users.

  40. Minimise unique domains, and use prefetching.

  41. <head> <link rel="dns-prefetch" href="//twitter.com"> <link rel="dns-prefetch" href="//api.twitter.com"> </head>

  42. HTTP Requests also add up.

  43. Need fast responses, use a worldwide CDN.

  44. None
  45. 6 simultaneous requests to the same domain.

  46. Only 2 in the old browsers.

  47. platform.twitter.com/ platform1.twitter.com/ platform2.twitter.com/ platform3.twitter.com/…? platform∞.twitter.com/…?

  48. Ugh, more DNS requests.

  49. Even slower 3-step handshake over SSL.

  50. Users lack upload bandwidth. Requests go up.

  51. Make fewer requests.

  52. Bundle JavaScript, styles, HTML.

  53. <!DOCTYPE html> <html> <head> <title>Twitter Tweet Button</title> <style type="text/css">/* minified

    stylesheet */</style> </head> <body> <a class="button">Tweet</a> <a class="count"></a> <script> // minified JavaScript </script> </body> </html>
  54. Use CSS3, and data: URI images.

  55. .btn { border-radius: 6px; background: linear-gradient(top, white, #DEDEDE); text-shadow: 0

    1px 0 rgba(255, 255, 255, .5); } .btn:hover, .btn:focus { box-shadow: inset 0 0 10px #000000; }
  56. None
  57. data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAoCAYAAABq13MpAAAGcklE[…]

  58. 1 HTTP request. Tweet

  59. Download smaller responses.

  60. Minify JavaScript with uglify-js or Closure.

  61. 85KB 45KB uglify

  62. Gzip all the things.

  63. 85KB 20KB gzip

  64. 85KB 20KB uglify gzip 14KB

  65. JS Frameworks are bigger than our product.

  66. But consider your goals, audience, and capability.

  67. Write tiny modules for LoadRunner & LoadBuilder

  68. Carefully organise bundles for lazy loading.

  69. We lazy load XDomain, JSON2, some rendering.

  70. Tailor build files to known environments

  71. We’re in 28 languages. Separate builds save 6KB.

  72. Loading from JS, so you have the information.

  73. Retina displays, data/png support, small screens…

  74. Download nothing at all.

  75. Render on the client to share cached templates.

  76. Cache aggressively, download once for all time.

  77. Hash filenames for <iframe> and dependencies.

  78. Avoid ?query=params, use #fragment=params.

  79. Blocking, and other ways to break the web.

  80. <script src="//platform.twitter.com/widgets.js"></script>

  81. None
  82. A script source times out, the page is left waiting.

  83. It could happen to any of us.

  84. Wherever possible, use non-blocking script code.

  85. <script src="//platform.twitter.com/widgets.js"></script>

  86. <script>!function (doc, script, id) { var js, first = doc.getElementsByTagName(script)[0];

    if (!doc.getElementById(id)) { js = doc.createElement(script); js.id = id; js.src = "//platform.twitter.com/widgets.js"; first.parentNode.insertBefore(js, first); } }(document,"script","twitter-wjs");</script>
  87. Doesn’t block and avoids duplicate downloads.

  88. We use this almost everywhere.

  89. Use script.js, lab.js, or loadrunner on your sites.

  90. The fastest JavaScript is no JavaScript.

  91. Embed codes are links to supported endpoints.

  92. We call them Web Intents. (Which is unfortunate.)

  93. None
  94. <a class="twitter-follow-button” href="https://twitter.com/benward">Follow Ben Ward</a>

  95. They accept the same parameters as the widgets.

  96. They’re there if something bad happens.

  97. They’re there if you don’t want our script at all.

  98. All major Twitter actions represented by <a href>.

  99. Progressive enhancement at the product core.

  100. The entire product is an enhancement.

  101. We build for the web.

  102. Thank you.

  103. Photo credits: http://flic.kr/y/nLCZEt

  104. Questions. Also, answers.