Building Fast 3rd-Party Webapps Lessons learned from the Meebo Bar Martin Hunt and Marcus Westin O'Reilly Velocity Web Performance and Operations Conference 24 June 2010 marcus@meebo-inc.com martinh@meebo-inc.com The Meebo Bar A customizable site bar with real-time social interaction Meebo Bar, a 3rd Party Webapp JavaScript, CSS, Images & HTML Interacts with the page Loads on every page How do we make it run fast? How do we make it respectful? 3rd Party Webapps The Challenge Do • Load lots of features • Load features fast Without • Blocking rendering or onload • Affecting User Experience How? 3rd Party Webapps: How? Tools Techniques • How to initialize a webapp Asynchronous & non-blocking o • Defer Execution Minimize impact when loading • CSS and Images Crush, Combine, Avoid • Perceived Performance Testing and psychology Meebo Bar embed code • executes in ~10ms o no blocking network requests o no dependency on our server • less than 1200 characters • gzips to about 700 bytes • embedded directly in page HTML or JS • executes even if our servers are not reachable Initializing 3rd Party Webapps Inline JS <script src=""> easy for publishers to add blocks the page in all browsers Iframe <iframe src=""> load an HTML file in an iframe Requires HTML file on the hosting site XMLHttpRequests Asynchronous, nonblocking same-domain in most browsers Script Tag append a script tag using JavaScript to the head of the document Commonly accepted, but... Accepted script loading code var head = document.getElementsByTagName('head')[0], el = document.createElement('script'); el.src = "http://www.myDom.ain/myScript.js"; head.appendChild(el); good: cross domain (we're 3rd party content!) good: doesn't block network traffic Don't block the page! Script Tag Append can block scripts in Firefox! blocks other scripts in Firefox • scripts execute in order • all scripts on the page block until the appended script downloads and executes • (defer attribute supported in FF3.5+) blocks onload event in all browsers are there alternative nonblocking methods? Iframed JS 1. Iframes load HTML, not JS 2. Cross iframe communication is same-domain only (non-HTML5 browsers) 3. Window onload event fires after all iframes load Iframed JS - the solution var iframe = document.createElement('iframe'), doc = iframe.contentWindow.document; doc.open().write('<body onload="appendScriptTag()">') doc.close() More About Iframes iframe creation overhead? Creating one DOM node o Chrome < 1ms o Firefox, Safari ~1ms o IE ~5ms Sandboxed JavaScript • 3rd party code will not break webpage code • Webpage code will not break 3rd party code! for (var i in x) {} Defer Execution Defer Execution Lots of stuff happens in a browser while loading a page Then, relatively little happens... Take advantage of this! Defer Execution Example In-page sharing Defer Execution Example In-page sharing Defer Execution Example In-page sharing Defer Execution Example In-page sharing Naive implementation function makeSharable(elements) { for (var i=0; i < elements.length; i++) { var element = elements[i]; var metadata = lookupMetadata(element); element.on('mousedown', startDrag, metadata); } } function lookupMetadata(el) { do { inspectElement(el) } while(el = el.parentNode) } O(N*M) O(N) O(M) Deferred implementation function initShare() { document.on('mousedown', function(e) { var el = e.target || e.srcElement if (!el.getAttribute('meeboSharable')) { return; } var metadata = lookupMetadata(el); document.on('mousemove', handleDrag, metadata); document.on('mouseup', stopDrag, metadata); }); } Page finishes loading O(1) Modularize & Lazy Load users don't need all features immediately 1-1 Messaging connect to all the IM networks Social Networking Broadcasting publishers send new content to users receive updates about your friends' activities Sharing Site Widgets share site content to Facebook, Twitter, Buzz, and other sites site-specific widgets: videos, menus, navigation tools, etc. Modularize & Lazy Load Also applies to images and CSS! Careful: Loading images can create a lot of HTTP requests Loading Images Spriting and preloading is hard Still creates additional HTTP requests Difficult to automate Embed images into CSS instead DataURIs and MHTML files Details on the Meebo devblog (http://mee.bo/cssimages) Use Vector Graphics Vector graphics are supported in all major browsers • • • • • Firefox 3+ Opera 9.5+ IE 6+ Safari 3+ Chrome With images Without images Tools - use them! Profilers • DynaTrace (IE) • Speed tracer (Chrome) • Firebug (FF) • Safari 5/WebKit Preprocess if possible • if multiple clients are doing the exact same task, run it on the server • generate content offline Compilers • Closure Compiler Perceived Performance Quick loading content on a slow page appears to be the cause of the slow page Delaying interface drawing can look slow or broken Do not forget: Even asynchronous loading slows down a page. Keep payloads minimal and always monitor performance! Highlights • • • • • Always compress and minify content Use an IFrame to load the main script payload Defer execution until needed Defer content download until needed Remove HTTP requests by combining content o Embed images into CSS o Use vector graphics Questions? marcus@meebo-inc.com martinh@meebo-inc.com