Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Fronteers

Alex MacCaw
February 26, 2014
100

 Fronteers

Alex MacCaw

February 26, 2014
Tweet

Transcript

  1. A second is a 0.65% increase in bounce rate 2,000

    ms delay on Bing search pages decreased per-user revenue by 4.3%! It’s really easy justify spending time on speed optimizations, because it directly affects your bottom line.
  2. “Speed is the second biggest engagement driver on the internet

    - just after perceived speed.” - Thomas Gorissen
  3. Delay User reaction 0 - 100ms Instant 100 - 300ms

    Feels Sluggish 300 - 1000ms Machine is working... 1s + Mental Context Switch 10s + I’ll come back later
  4. # Total Size (k) Number of Elements CSS Rules Image

    Files Script Lines Render time (ms) Site #1 3,697 1,504 1,392 41 77,768 Site #2 2,278 1,100 5,325 29 39,183 Site #3 1,061 2,673 1,105 66 12,643 Site #4 1,812 4,252 1,672 12 10,284 Site #5 1,372 900 3,902 6 38,269 Top five travel sites - Priceline/Kayak/Travelocity/Orbit Study done by Jatinder Mann at Microsoft. Changes a factor of 4.
  5. # Total Size (k) Number of Elements CSS Rules Image

    Files Script Lines Render time (ms) Site #1 3,697 1,504 1,392 41 77,768 2,700 Site #2 2,278 1,100 5,325 29 39,183 2900 Site #3 1,061 2,673 1,105 66 12,643 2500 Site #4 1,812 4,252 1,672 12 10,284 2600 Site #5 1,372 900 3,902 6 38,269 1500 Many developers would assume that the fastest site would be the one with the least number of formatted lines of JavaScript, like Site #4, or the one with the least bytes downloaded, like Site #3. However, that’s not the case. Site #5 is actually the fastest, even though it has more JavaScript and bytes downloaded.
  6. The execution of a web program primarily involves three tasks:

    fetching resources, page layout and rendering, and JavaScript execution. Notice that site 5 renders the quickest, and evaluates JavaScript the quickest.
  7. Resource Waterfall Dark green is DNS resolution. Orange is TCP

    handshake. Green is the HTTP request and Blue the time taken to download a resource. Notice that while monocle.io is being fetched, new HTTP requests are being dispatched. HTML is parsed incrementally. Scheduling of when the resource is fetched is in large part determined by the structure of the markup.
  8. Resource Waterfall DNS resolution & handshake You can see that

    DNS resolution and TCP handshaking is actually the bottleneck in many network requests. In other words bandwidth is not the limiting factor here, but network roundtrip latency between server and client. You can see further requests down the page don’t need to do DNS resolution / TCP handshake because of keepalive.
  9. Resource Waterfall The other thing to notice is that rendering

    on the client is taking up about half the time, and network the other half.
  10. “eliminate and reduce unnecessary network latency, and minimize the amount

    of transferred bytes” - Ilya Grigorik User only gets value when work is painted to the screen.
  11. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client
  12. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client You need to respond as quick as possible. Google search actually returns the header of the page before it’s even parsed the request. You’re only as fast as your weakest link. Do not preload data / do lots of SQL queries in first request. Put that in a second (async) script.
  13. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client Reuse established connections. TCP handshakes are expensive. Three way SYN/SYN ACK/ACK. Especially if there’s SSL negotiation. It’s enabled by default in HTTP 1.1
  14. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client Can cost you 200ms at least. 63% of the top websites have a top level redirect.
  15. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client Put the data as close as possible to people. Reduce the hops. Especially with static resources.
  16. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client Average website has 777k of resources. The vast amount of them are images/ JavaScript. No code is faster than no code. According to HTTP Archive, an average page is now composed of 90+ individual resources.
  17. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client Smaller assets. Gzip already remove duplications, but minifying JS will actually rewrite it.
  18. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client TCP handshakes are expensive. Three way SYN/ACK/ACK. SSL is even more expensive. Latency is the bottleneck.
  19. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client If you GZip something before giving it to a CDN, then you don’t have to deal with the server overheads of it. Not turned on by default in nginx/apache.
  20. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client Set an ‘Expires’ header for a year. Fingerprint assets with a MD5 checksum of their data.
  21. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client Only 1% of Ajax requests are cached.
  22. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client 58% of the web has duplicate code on it. I found two versions of jQuery on Stripe.
  23. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client More than half of the bytes on most websites today are images. Avoid large images. Remember PNGs are lossless. Compress jpgs. Sprites.
  24. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Client Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client In IE, set the X-UA-Compatible header. This will make it render HTML more intelligently. Much faster to put it in the header than a tag.
  25. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Client Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client You want the browser to issue that network request first. Browser will also block painting until that network request is done. Inline styles invalidate the CPU cache. Only keep the required styles for the page. Don’t share between pages unless theme.
  26. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Client Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use defer Delay loading unnecessary JS Client Remove *all* blocking JavaScript from the page. Use ‘defer’ attribute. Sometimes causes bugs. Remove JS that doesn’t need to be there on page load, like analytics.
  27. Quick response Use KeepAlive Don’t redirect Use CDNs Reduce resources

    Minify JavaScript / CSS Concat resources GZip responses Fingerprint & cache static assets Cache Ajax requests Remove duplicate code Minimize & compress images Network Client Use standards mode for IE Put stylesheets first Stop blocking JavaScript, use async Delay loading unnecessary JS Client Remove things like google analytics and mixpanel until the window ‘load’ event.
  28. #1. Use ngx_pagespeed throwing ngx_pagespeed at an app will automate

    most of the network optimizations you should be making.
  29. • Image optimization: stripping meta-data, dynamic resizing, recompression • CSS

    & JavaScript minification, concatenation, inlining, and outlining • Small resource inlining • Deferring image and JavaScript loading • HTML rewriting • Cache lifetime extension #1. Use ngx_pagespeed throwing ngx_pagespeed at an app will automate most of the network optimizations you should be making.
  30. #2. Don’t use large cookies throwing ngx_pagespeed at an app

    will automate most of the network optimizations you should be making.
  31. GET /posts/you-must-try-and-then-you-must-ask-the-akamai-blog HTTP/1.1 Host: monocle.io Connection: keep-alive Cache-Control: no-cache Accept:

    text/html,application/xhtml+xml,application/ xml;q=0.9,image/webp,*/*;q=0.8 Pragma: no-cache Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 #2. Don’t use large cookies Don’t store session data in large cookies on the client. Just use a session ID.
  32. Cookie: mp_c4d87fc5196ab5af8545f3669063cf08_mixpanel=%7B%22distinct_id%22%3A%20%229b34ce05- ca4f-49bc-98a5-6d8c4a070ae5%22%2C%22%24initial_referrer%22%3A%20%22%24direct%22%2C %22%24initial_referring_domain%22%3A%20%22%24direct%22%7D; _ga=GA1.2.1343163750.1375193368; mp_2f5bb6e9a3a423678df4d18e5f268000_mixpanel=%7B%22distinct_id%22%3A%20%229b34ce05- ca4f-49bc-98a5-6d8c4a070ae5%22%2C%22%24initial_referrer%22%3A%20%22%24direct%22%2C %22%24initial_referring_domain%22%3A%20%22%24direct%22%2C%22__mps%22%3A%20%7B%7D%2C%22__mpso%22%3A%20%7B %7D%2C%22__mpa%22%3A%20%7B%7D%2C%22__mpap%22%3A%20%5B%5D%2C%22%24search_engine%22%3A%20%22google%22%7D; rack.session=BAh7C0kiD3Nlc3Npb25faWQGOgZFVEkiRWQ5ODY0OTEwOWViNjljZTM1MWMz

    %0AMzU2ODgyZDhjN2E0Y2NjNzJjZjE1MzA4YWVmMjY5ZTEyMDg2NzU0MjAwNWUG %0AOwBGSSIPY3NyZi50b2tlbgY7AFRJIkVhZGU0MjFiYzg5ZTIyZGE5YzY5NDA1%0AOTA3ZjM5NzliZTg2Y2E2NzA4NWZiNzM0NjVkMGE5 YTc4YzFjOGIyNGI5BjsA%0ARkkiCWNzcmYGOwBGSSJFMmEzZjcxOThkY2ExMDA4OGU3ZWEyYjk0MTg1MzJl %0AMDg3NzMyNGU0Y2Y1YWFjYjM0OGFlMGRiMzU3Y2QxMGMxYgY7AEZJIgpvYXV0%0AaAY7AFR7BkkiDHR3aXR0ZXIGOwBUewZJIhdjYWxs YmFja19jb25maXJtZWQG%0AOwBUVEkiDHVzZXJfaWQGOwBGSSIpOWIzNGNlMDUtY2E0Zi00OWJjLTk4YTUt %0ANmQ4YzRhMDcwYWU1BjsAVEkiD3JhbmRvbWl6ZWQGOwBGVA%3D%3D%0A--b7d6f828d50b640902913b2ca3c47422eb02544f GET /posts/you-must-try-and-then-you-must-ask-the-akamai-blog HTTP/1.1 Host: monocle.io Connection: keep-alive Cache-Control: no-cache Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Pragma: no-cache Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 #2. Don’t use large cookies Don’t store session data in large cookies on the client. Just use a session ID.
  33. Cookie: mp_c4d87fc5196ab5af8545f3669063cf08_mixpanel=%7B%22distinct_id%22%3A%20%229b34ce05- ca4f-49bc-98a5-6d8c4a070ae5%22%2C%22%24initial_referrer%22%3A%20%22%24direct%22%2C %22%24initial_referring_domain%22%3A%20%22%24direct%22%7D; _ga=GA1.2.1343163750.1375193368; mp_2f5bb6e9a3a423678df4d18e5f268000_mixpanel=%7B%22distinct_id%22%3A%20%229b34ce05- ca4f-49bc-98a5-6d8c4a070ae5%22%2C%22%24initial_referrer%22%3A%20%22%24direct%22%2C %22%24initial_referring_domain%22%3A%20%22%24direct%22%2C%22__mps%22%3A%20%7B%7D%2C%22__mpso%22%3A%20%7B %7D%2C%22__mpa%22%3A%20%7B%7D%2C%22__mpap%22%3A%20%5B%5D%2C%22%24search_engine%22%3A%20%22google%22%7D; rack.session=BAh7C0kiD3Nlc3Npb25faWQGOgZFVEkiRWQ5ODY0OTEwOWViNjljZTM1MWMz

    %0AMzU2ODgyZDhjN2E0Y2NjNzJjZjE1MzA4YWVmMjY5ZTEyMDg2NzU0MjAwNWUG %0AOwBGSSIPY3NyZi50b2tlbgY7AFRJIkVhZGU0MjFiYzg5ZTIyZGE5YzY5NDA1%0AOTA3ZjM5NzliZTg2Y2E2NzA4NWZiNzM0NjVkMGE5 YTc4YzFjOGIyNGI5BjsA%0ARkkiCWNzcmYGOwBGSSJFMmEzZjcxOThkY2ExMDA4OGU3ZWEyYjk0MTg1MzJl %0AMDg3NzMyNGU0Y2Y1YWFjYjM0OGFlMGRiMzU3Y2QxMGMxYgY7AEZJIgpvYXV0%0AaAY7AFR7BkkiDHR3aXR0ZXIGOwBUewZJIhdjYWxs YmFja19jb25maXJtZWQG%0AOwBUVEkiDHVzZXJfaWQGOwBGSSIpOWIzNGNlMDUtY2E0Zi00OWJjLTk4YTUt %0ANmQ4YzRhMDcwYWU1BjsAVEkiD3JhbmRvbWl6ZWQGOwBGVA%3D%3D%0A--b7d6f828d50b640902913b2ca3c47422eb02544f GET /posts/you-must-try-and-then-you-must-ask-the-akamai-blog HTTP/1.1 Host: monocle.io Connection: keep-alive Cache-Control: no-cache Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Pragma: no-cache Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 #2. Don’t use large cookies Don’t store session data in large cookies on the client. Just use a session ID.
  34. jQuery(function(){ var options = <%== @options.to_json %>; window.app = new

    App(options); }); get '/setup.js' do content_type 'application/javascript' @options = { user: current_user, posts: Post.popular.all, } erb :setup end
  35. <link rel="prerender" href="http://example.com"/> <link rel="prefetch" href="http://example.com"/> <link rel="dns-prefetch" href="http://example.com"/> DNS-prefetch

    will just do a DNS resolution. Prefetch will go and fetch the page’s data. Supported in Firefox/ Chrome. Prerender will actually go and fetch and pre render the page. subresource?
  36. prerender = $('<link rel="prerender" />') prerender.attr('href', url) prerender.appendTo('body') You can

    actually use these things programatically. For monocle.io, I detect if a person has hovered over an article, and pre-render it’s contents. When they click on the link, Chrome will actually just swap in and out the page - instant.
  37. You can only pre-render one page at a time. You

    can see this happening inside Chrome’s Task manager.
  38. You can only pre-render one page at a time. You

    can see this happening inside Chrome’s Task manager.
  39. Let’s talk about Rendering Rendering is often unoptimized, and is

    less talked about. It’s the other bottleneck.
  40. Reflows Reflow in a web browser refers to the process

    where the render engine calculates positions and geometries of elements in the document. In other words it figures out how elements should be displayed before the paint. It’s also known as redraw in WebKit.
  41. This is a visualization of Gecko rendering the mozilla.org homepage,

    calculating the layout and position of elements. at 0:16 something happens, which invalidates the layout and means it has to re-calculate the whole thing again. Unnecessary - this is the kind of thing we want to avoid.
  42. What triggers a reflow? Adding/removing/showing/hiding DOM nodes. User actions such

    as scrolling/ resizing etc. Adding classes to DOM nodes.
  43. What triggers a reflow? clientHeight, clientLeft, clientTop, clientWidth, focus(), getBoundingClientRect(),

    getClientRects(), innerText, offsetHeight, offsetLeft, offsetParent, offsetTop, offsetWidth, outerText, scrollByLines(), scrollByPages(), scrollHeight, scrollIntoView(), scrollIntoViewIfNeeded(), scrollLeft, scrollTop, scrollWidth, scrollTo(), scrollX, scrollY Accessing any of these properties/functions can cause a reflow. Adding/removing/ showing/hiding DOM nodes. User actions such as scrolling/resizing etc. Adding classes to DOM nodes. http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html
  44. Reflows are often expensive Reflows are sometimes unavoidable, but you

    can reduce their impact. Three places you really notice reflows. First page load. Animation loops. Scrolling. We need to optimize all three use cases.
  45. Change classes as low in the DOM tree as possible

    Change classes as low in the DOM tree as possible and thus limit the scope of the reflow to as few nodes as possible.
  46. // Read var h1 = element1.clientHeight + 'px'; // Write

    element2.style.height = h1; // Document reflow... // Read var h2 = element3.clientHeight + 'px'; // Write element4.style.height = h2; // Document reflow... Avoid DOM thrashing
  47. // Read var h1 = element1.clientHeight + 'px'; var h2

    = element3.clientHeight + 'px'; // Write element2.style.height = h1; element4.style.height = h2; // Document reflow... Avoid DOM thrashing
  48. // Read var h1 = element1.clientHeight + 'px'; // Write

    requestAnimationFrame(function() { element2.style.height = h1; }); // Read var h2 = element3.clientHeight + 'px'; // Write requestAnimationFrame(function() { element4.style.height = h2; }); Avoid DOM thrashing
  49. function slowLoop() { setInterval(function(){ // Animation loop }, 10); };

    function fasterLoop() { // Animation loop requestAnimationFrame(fasterLoop); }; You have to make sure that you’re causing reflows when it’s convenient for the browser. The interval is firing faster than the browser’s refresh rate - will cause a lot of unnecessary work that won’t be painted.
  50. function slowLoop() { setInterval(function(){ // Animation loop }, 10); };

    function fasterLoop() { // Animation loop requestAnimationFrame(fasterLoop); }; In fact this advice isn’t limited to animation loops. If you’re deferring any kind of rendering, use it - much kinder to the browser. You can easily shim it in older browsers.
  51. var debounce = function(callback, wait) { if (wait == null)

    wait = 300; var timeout = null; return function() { var args = arguments; var ctx = this; var later = function() { callback.apply(ctx, args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } Debouncing scroll events
  52. var onScroll = function () { /* ... */ };

    $('#element').scroll(debounce(onScroll)); Make sure your onScroll function is as fast as possible. Maybe even put any rendering it does in a requestAnimationFrame.
  53. Use onbeforeunload sparingly onbeforeunload is often used to warn the

    user when there are pending Ajax requests. However, DO NOT set it at all times, only when there are pending requests. Really messes up Chrome’s caching.
  54. var addHandler = function() { window.onbeforeunload = function() { return

    'There are some pending network requests...'; }; }; var removeHandler = function() { window.onbeforeunload = null; }; onbeforeunload is often used to warn the user when there are pending Ajax requests. However, DO NOT set it at all times, only when there are pending requests. Really messes up Chrome’s caching.
  55. var addHandler = function() { window.onbeforeunload = function() { return

    'There are some pending network requests...'; }; }; var removeHandler = function() { window.onbeforeunload = null; }; $(document).ajaxSend(function() { addHandler(); }); $(document).ajaxComplete(function() { removeHandler(); }); onbeforeunload is often used to warn the user when there are pending Ajax requests. However, DO NOT set it at all times, only when there are pending requests. Really messes up Chrome’s caching.
  56. Essentially, do less • Don’t resize images in CSS •

    Avoid complex CSS selectors • Don’t use inline styles • Batch up DOM communication • Take elements out of flow when animating
  57. Solving a crime Solving a performance problem is like solving

    a crime. First you have to collect evidence. Then you have to interrogate suspects. Lastly you need to collect forensics.
  58. Solving a crime Let’s look for evidence Solving a performance

    problem is like solving a crime. First you have to collect evidence. Then you have to interrogate suspects. Lastly you need to collect forensics.
  59. The crime scene is Sourcing.io, an app I’m building to

    help source engineers. Notice we have an infinite table - people are loaded in as the table is scrolled.
  60. We can open up the Timeline, hit record, then play

    around with our application. In this case, we’re going to scroll down the list of people, loading more in.
  61. Low and behold, we’ve got a performance issue. See, we’re

    almost never hitting 60fps. Look at all that purple - lots of time spent rendering.
  62. If we analysis it closer, we can see an expensive

    whole document layout triggered by adding a class - specifically the showLoading function on PeopleTable.
  63. If we analysis it closer, we can see an expensive

    whole document layout triggered by adding a class - specifically the showLoading function on PeopleTable.
  64. showLoading: => @$el.addClass('loading') This is because I’m trying to be

    a bit too clever, and whenever the people table is loading, I add a class to it. And vica versa when the Ajax request has completed. It’s a fairly expensive operation though.
  65. This is because I’m trying to be a bit too

    clever, and whenever the people table is loading, I add a class to it
  66. Detecting a memory leak. The profile for a normal application

    should look like a saw tooth. Memory is allocated and then the garbage collector kicks in.
  67. Here’s a case where we might have a memory issue.

    You can see more and more DOM nodes are being added to the page. Looks like we need to do a bit of manual garbage collection, and delete some of those DOM nodes outside the viewport.
  68. Collect JavaScript CPU profile, hit start. Then perform some sort

    of action in your app - for example in Monocle, selecting a post. Then click ‘stop’.
  69. You can see which operations are taking the longest. Here,

    anything to do with communicating with the DOM takes the longest. The sort order is ‘Bottom Up’, listing functions by impact on performance. You can also see timings by percentage, which is useful for exposing bottlenecks.
  70. Unoptimized code The yellow exclamation marks indicate where the V8

    compiler falls back to ‘full’ mode, rather than ‘optimized’ mode. This can happen for a variety of reasons, but in this case it’s because jQuery’s extend has a try/catch in it. If you hover, it’ll tell you what’s wrong.
  71. You can also drill down into events, and see what

    caused them. In this case WebKit’s ‘scrollIntoViewIfNeeded’ function is taking up about half of our render time.
  72. We can take two snapshots. And then compare them. You

    can see the difference in number of objects (via the delta). Again, this can help you drill down on a memory leak.
  73. Lay down the law To help prevent performance crimes, let’s

    lay down the law. We can continually record performance, and notify you when something changes.
  74. PageSpeed Insights PageSpeed insights is a service created by Google

    that’ll tell you a lot about the performance of your web app.
  75. require 'nestful' require 'csv' page_speed = Nestful::Mash.get( 'https://www.googleapis.com/pagespeedonline/v1/runPagespeed', url: 'http://monocle.io',

    key: ENV['GOOGLE_SECRET'] ) CSV.open('stats.csv', 'a') do |csv| csv << [Time.now, page_speed.score] end Here’s an example of how you could access the API in Ruby. You could tie this in with a post-deploy hook, so it records data after every deploy. Then you can look through the data and identify deploys that change the performance significantly and get an early heads up. Would be pretty awesome if this was in a service anyone?
  76. Stick to good defaults, but keep performance in mind It’s

    pretty easy to stick to good network defaults. Remember to not forgot to optimize rendering.