Enhance Web Performance

2,061 views

Published on

Published in: Technology

Enhance Web Performance

  1. 1. Enhance Web Performance Adam Lu [email_address] Y!ID: adamlu86 http://adamlu.com/
  2. 2. The Performance Golden Rules 80-90% of the end-user response time is spent on the front-end.
  3. 3. High Performance Web Sites <ul><li>Make fewer Http Requests </li></ul><ul><li>Style sheets at the top </li></ul><ul><li>Placing scripts. </li></ul><ul><li>Avoid CSS Expressions </li></ul><ul><li>Make CSS and JS external </li></ul><ul><li>Minification </li></ul><ul><li>Make Ajax cacheable </li></ul><ul><li>Miscellaneous Tips </li></ul>
  4. 4. Make fewer Http Requests <ul><li>Combine CSS and JavaScript files </li></ul><ul><li>Css Sprites – Used for snappy image replacement </li></ul><ul><ul><li>Combine static images into a single image file. </li></ul></ul><ul><ul><li>Use Css to cut and place. </li></ul></ul><ul><ul><li>CSS properties background-image and background-position are used. </li></ul></ul><ul><ul><ul><li>background:transparent url(“sprite.png”;) no-repeat </li></ul></ul></ul><ul><ul><ul><li>background-position: 0 -30px </li></ul></ul></ul>
  5. 5. Style sheets at the top <ul><li>Use <link> tags to include stylesheets. </li></ul><ul><li>Neglect embedded styles and inline styles too. </li></ul><ul><li>Push style sheet inclusion into the head. </li></ul><ul><li>User perception of the page loading faster is important </li></ul>
  6. 6. Placing scripts <ul><li>Move script inclusion as low as possible </li></ul><ul><li>Don’t scatter inline scripts </li></ul><ul><li>Progressive rendering. </li></ul><ul><li>Scripts don’t download parallely. But in IE, it can be achieved by Dom inlucde. </li></ul><ul><ul><li>window.onload = function () { </li></ul></ul><ul><ul><li>var script = document.createElement(“script”); </li></ul></ul><ul><ul><li>script.src = ...; </li></ul></ul><ul><ul><li>document.body.appendChild(script); </li></ul></ul><ul><ul><li>}; </li></ul></ul>
  7. 7. Avoid CSS Expressions <ul><li>Option available only in IE. </li></ul><ul><ul><li>width:expression(document.body.clientWidth < 550 ? “450px” : “100%” ); </li></ul></ul><ul><li>Use event handlers instead. </li></ul><ul><ul><li>Eg: element.addEventListener(‘<event>’, <handler to call>, <capturing/bubbling>). </li></ul></ul><ul><ul><li>Eg: window.addEventListener(‘resize’, changeWidth, true). </li></ul></ul><ul><ul><li>element.removeEventListener is used to remove the event. </li></ul></ul><ul><ul><li>In IE, attachEvent must be used instead. </li></ul></ul>
  8. 8. Make JS &CSS external <ul><li>Inline – Using <@include> or import make the html doc big. </li></ul><ul><li>External using <script> and <link> tags </li></ul><ul><ul><li>Increases Http requests (bad) </li></ul></ul><ul><ul><li>Helps caching (good) </li></ul></ul>
  9. 9. Minification <ul><li>Minify external javascript </li></ul><ul><ul><li>Remove comments and spaces </li></ul></ul><ul><li>Minify inline scripts </li></ul><ul><li>Obfuscation- Not recommended. Not safe </li></ul><ul><li>Let the dev code not be minified. Should have comments/spaces for maintainability. Use Tools before moving code to production. </li></ul><ul><ul><li>Js Min </li></ul></ul><ul><ul><li>YUI Compressor. </li></ul></ul>
  10. 10. Make Ajax cacheable <ul><li>No synchronous requests. </li></ul><ul><li>Use GET for AJAX Requests </li></ul><ul><ul><li>Post is a two step process (Sending the headers first and then sending data) ‏ </li></ul></ul><ul><li>Favor JSON over XML as your data exchange format. </li></ul><ul><li>AJAX pattern: </li></ul><ul><ul><ul><li>Update the UI when the request gets sent. </li></ul></ul></ul><ul><ul><ul><li>Lock the UI/data structures with the finest possible granularity. </li></ul></ul></ul><ul><ul><ul><li>Let the user know that something is happening. </li></ul></ul></ul><ul><ul><ul><li>Let the user know why a UI object is locked. </li></ul></ul></ul><ul><ul><ul><li>Unlock the UI/data structures when the outcome is successful. </li></ul></ul></ul><ul><ul><ul><li>Handle error cases gracefully. </li></ul></ul></ul><ul><li>Lazy loading - http://ajaxpatterns.org/On-Demand_Javascript </li></ul>
  11. 11. Miscellaneous Tips <ul><li>Optimize Table Layout </li></ul><ul><ul><ul><li>Goal: allow the rendering engine to start rendering a table before it has received all the data </li></ul></ul></ul><ul><ul><ul><li>Use table-layout:fixed </li></ul></ul></ul><ul><ul><ul><li>Explicitly define a COL element for each column </li></ul></ul></ul><ul><ul><ul><li>Set the WIDTH attribute on each col </li></ul></ul></ul><ul><li>Close Your HTML Tags to Speed Up Parsing </li></ul><ul><li>Regular expression </li></ul><ul><ul><ul><li>Use regular expression literals. </li></ul></ul></ul><ul><ul><ul><ul><li>Eg: if (/loaded|complete/.test(status)) {...} </li></ul></ul></ul></ul><ul><ul><ul><li>Stick to simple patterns </li></ul></ul></ul><ul><li>In IE, Use Array.join(“”) rather than string concatenation </li></ul>
  12. 12. Miscellaneous Tips <ul><li>In case of changing lot of styles in js, try swapping styleclasses. </li></ul><ul><ul><li>More maintainable: change the CSS class name of an element. obj.className=‘<class>’; </li></ul></ul><ul><li>Consider using the onmousedown event instead of the onclick event </li></ul><ul><li>Document Tree Modification. </li></ul><ul><ul><li>InnerHTML Way is Faster than Usal Way </li></ul></ul>
  13. 13. Speed Up Javascript
  14. 14. There are four main reasons why a script can take too long to execute <ul><li>Too much happening in a loop. </li></ul><ul><li>Too much happening in a function. </li></ul><ul><li>Too much recursion. </li></ul><ul><li>Too much DOM interaction. </li></ul>
  15. 15. Too much happening in a loop <ul><li>for(var i=0; i < items.length; i++){ </li></ul><ul><li>process(items[i]); </li></ul><ul><li>} </li></ul><ul><li>function chunk(array, process, context){ </li></ul><ul><li>var items = array.concat(); //clone the array </li></ul><ul><li>setTimeout(function(){ </li></ul><ul><li>var item = items.shift(); </li></ul><ul><li>process.call(context, item); </li></ul><ul><li>if (items.length > 0){ </li></ul><ul><li>setTimeout(arguments.callee, 100); </li></ul><ul><li>} </li></ul><ul><li>}, 100); </li></ul><ul><li>} </li></ul>
  16. 16. Too much happening in a function <ul><li>function bubbleSort(items){ for (var i=items.length-1; i >= 0; i--){ for (var j=i; j >= 0; j--){ if (items[j] < items[j-1]){ var temp = items[j]; items[j] = items[j-1]; items[j-1] = temp; } } } } </li></ul><ul><li>function bubbleSort(array, onComplete){ var pos = 0; (function(){ var j, value; for (j=array.length; j > pos; j--){ if (array[j] < array[j-1]){ value = data[j]; data[j] = data[j-1]; data[j-1] = value; } } pos++; if (pos < array.length){ setTimeout(arguments.callee,10); } else { onComplete(); } })(); } </li></ul>
  17. 17. Too much happening in a function <ul><li>function fibonacci (n) { return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); }; </li></ul><ul><li>function memoizer(memo, fundamental) { var shell = function (n) { var result = memo[n]; if (typeof result !== 'number') { result = fundamental(shell, n); memo[n] = result; } return result; }; return shell; }; </li></ul><ul><li>var fibonacci = memoizer([0, 1], function (recur, n) { return recur(n - 1) + recur(n - 2); }); </li></ul><ul><li>fibonacci(40); </li></ul>
  18. 18. Too much recursion <ul><li>function merge(left, right){ var result = []; while (left.length > 0 && right.length > 0){ if (left[0] < right[0]){ result.push(left.shift()); } else { result.push(right.shift()); } } return result.concat(left).concat(right); } </li></ul><ul><li>//recursive merge sort algorithm </li></ul><ul><li>function mergeSort(items){ if (items.length == 1) { return items; } var middle = Math.floor(items.length / 2), left = items.slice(0, middle), right = items.slice(middle); return merge(mergeSort(left), mergeSort(right)); } </li></ul><ul><li>//iterative merge sort algorithm </li></ul><ul><li>function mergeSort(items){ if (items.length == 1) { return items; } var work = []; for (var i=0, len=items.length; i < len; i++){ work.push([items[i]]); } work.push([]); //in case of odd number of items for (var lim=len; lim > 1; lim = (lim+1)/2){ for (var j=0,k=0; k < lim; j++, k+=2){ work[j] = merge(work[k], work[k+1]); } work[j] = []; //in case of odd number of items } return work[0]; } </li></ul>
  19. 19. Too much DOM interaction <ul><li>Reflow happens at various points in time: </li></ul><ul><ul><li>Initial page load. </li></ul></ul><ul><ul><li>Browser window resize. </li></ul></ul><ul><ul><li>DOM nodes added or removed. (When you add or remove a DOM node. ) </li></ul></ul><ul><ul><li>Layout styles applied. (When you apply a style dynamically (such as element.style.width=&quot;10px&quot;).) </li></ul></ul><ul><ul><li>Layout information retrieved. (When you retrieve a measurement that must be calculated, such as accessing offsetWidth, clientHeight, or any computed CSS value (via getComputedStyle() in DOM-compliant browsers or currentStyle in IE), while DOM changes are queued up to be made.) </li></ul></ul>
  20. 20. perform as many changes as possible outside of the live DOM structure <ul><li>for (var i=0; i < items.length; i++){ var item = document.createElement(&quot;li&quot;); item.appendChild(document.createTextNode(&quot;Option &quot; + i); list.appendChild(item); } </li></ul><ul><li>var fragment = document.createDocumentFragment(); for (var i=0; i < items.length; i++){ var item = document.createElement(&quot;li&quot;); item.appendChild(document.createTextNode(&quot;Option &quot; + i); fragment.appendChild(item); } list.appendChild(fragment); </li></ul>
  21. 21. remove a node from the live DOM before operating on it <ul><li>list.style.display = &quot;none&quot;; </li></ul><ul><li>for (var i=0; i < items.length; i++){ </li></ul><ul><li>var item = document.createElement(&quot;li&quot;); item.appendChild(document.createTextNode(&quot;Option &quot; + i); </li></ul><ul><li>list.appendChild(item); } </li></ul><ul><li>list.style.display = &quot;&quot;; </li></ul>
  22. 22. <ul><li>change the class using JavaScript rather than applying individual style changes manually </li></ul><ul><li>element.style.backgroundColor = &quot;blue&quot;; element.style.color = &quot;red&quot;; element.style.fontSize = &quot;12em&quot;; </li></ul><ul><li>element.className = &quot;newStyle&quot;; </li></ul><ul><li>cache results that you retrieve from the DOM </li></ul><ul><li>document.getElementById(&quot;myDiv&quot;).style.left = document.getElementById(&quot;myDiv&quot;).offsetLeft + document.getElementById(&quot;myDiv&quot;).offsetWidth + &quot;px&quot;; </li></ul><ul><li>var myDiv = document.getElementById(&quot;myDiv&quot;); myDiv.style.left = myDiv.offsetLeft + myDiv.offsetWidth + &quot;px&quot;; </li></ul>
  23. 23. Proccess the HTMLCollection type <ul><li>var divs = document.getElementsByTagName(&quot;div&quot;); </li></ul><ul><li>for (var i=0; i < divs.length; i++){ //infinite loop document.body.appendChild(document.createElement(&quot;div&quot;)); } </li></ul><ul><li>var divs = document.getElementsByTagName(&quot;div&quot;); </li></ul><ul><li>for (var i=0, len=divs.length; i < len; i++){ //not an infinite loop document.body.appendChild(document.createElement(&quot;div&quot;)); } </li></ul>
  24. 24. Fastest way to build an HTML string <ul><li>String concat </li></ul><ul><li>var arr = ['item 1', 'item 2', 'item 3', ...], list = '';   for (var i = 0, l = arr.length; i < l; i++) { list += '<li>' + arr[i] + '</li>'; }   list = '<ul>' + list + '</ul>'; </li></ul><ul><li>Array pushing </li></ul><ul><li>var arr = ['item 1', 'item 2', 'item 3', ...], list = [];   for (var i = 0, l = arr.length; i < l; i++) { list[list.length] = '<li>' + arr[i] + '</li>'; }   list = '<ul>' + list.join('') + '</ul>'; </li></ul><ul><li>Native join </li></ul><ul><li>var arr = ['item 1', 'item 2', 'item 3', ...];   var list = '<ul><li>' + arr.join('</li><li>') + '</li></ul>'; </li></ul>
  25. 25. Javascript good practice <ul><li>Always use “var” for declaration. </li></ul><ul><li>Feature detect rather that browser detect. </li></ul><ul><li>Use Object literal notation: </li></ul><ul><ul><ul><li>Var order = { </li></ul></ul></ul><ul><ul><ul><li>mode: ‘default’, </li></ul></ul></ul><ul><ul><ul><li>obj : { id:’1’, val:’10’}, </li></ul></ul></ul><ul><ul><ul><li>array1 : [‘1’, ‘2’, ‘3’], </li></ul></ul></ul><ul><ul><ul><li>show : function(elToshow) { </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><li>Use square bracket notation </li></ul><ul><ul><li>MyObject[“property”] rather than MyObject.property </li></ul></ul><ul><ul><li>Use dot notation for standard properties of objects </li></ul></ul><ul><ul><li>Square bracket notation to access properties which are defined as objects in the page. </li></ul></ul><ul><ul><ul><li>Good: document.forms[“formname”].elements[“input”].value </li></ul></ul></ul><ul><ul><ul><li>Bad : document.formname.inputname </li></ul></ul></ul>
  26. 26. Javascript good practice <ul><li>Avoid eval. Use JSON.parse(jsontext, reviver); </li></ul><ul><li>Use === and !== in place of == and !=. Because of type coercion. </li></ul><ul><li>Cache variables. </li></ul><ul><li>Falsy values in js. </li></ul><ul><ul><li>If (“”), if (0), if (null), if (undefined), if(NaN) are false. </li></ul></ul><ul><li>The Unary + Operator To TypeConvert To Number </li></ul><ul><ul><li>Eg: var input1 = document.getElementById(‘text1’).value; </li></ul></ul><ul><ul><li>var input2 = document.getElementById(‘text2’).value; </li></ul></ul><ul><ul><li>var value1 = (+input1)+(+input2) or var value1 = (input1-0)+(input2-0); </li></ul></ul><ul><li>Avoid Cluttering The Global Namespace. Use object literals. </li></ul><ul><li>Avoid “with” </li></ul><ul><li>Use JSON instead of XML </li></ul><ul><li>Use Correct <script> Tags </li></ul><ul><ul><li><script type=“text/javascript” src=”..”>, Language tag is deprecated. </li></ul></ul>More On http://www.javascripttoolbox.com/bestpractices/
  27. 27. Minify HTML
  28. 28. Minify HTML <ul><li>Placing Inline Elements Inside Block Elements </li></ul><ul><li>Using <strong> and <em> instead of <b> and <i> for Bolding and Italicizing </li></ul><ul><li>Using <del> and <ins> instead of <s> and <strike> for showing deleted and inserting text </li></ul><ul><li>Using Less Line Breaks </li></ul><ul><li>Avoid using inline styling </li></ul><ul><li>Inline Images data:URL scheme ---- disobedient </li></ul>
  29. 29. Css Guidelines
  30. 30. Css Guidelines <ul><li>What’s the key selector? </li></ul><ul><li>a > img {//props} div > p </li></ul><ul><li>How the Style System Matches Rules </li></ul><ul><li>Style Computation – R to L </li></ul><ul><li>Four types of css </li></ul><ul><ul><li>ID Rules button#backButton { } 、 #urlBar[type=“autocomplete”] { } treeitem > treerow > treecell 、 #myCell:active { } </li></ul></ul><ul><ul><li>Class Rules button.toolbarButton { } 、 .fancyText { } 、 menuitem > .menu-left[checked=&quot;true&quot;] { } </li></ul></ul><ul><ul><li>Tag Rules td { } 、 treeitem > treerow { } 、 input[type=&quot;checkbox&quot;] { } </li></ul></ul><ul><ul><li>Universal Rules [hidden=“true”] { } 、 * { } 、 tree > [collapsed=&quot;true&quot;] { } </li></ul></ul>
  31. 31. Guidelines for Efficient CSS <ul><li>Avoid Universal Rules!. </li></ul><ul><li>Don’t qualify ID/class-categorized rules with tag/class names BAD - button#backButton { } GOOD - #backButton { } </li></ul><ul><li>Tag-categorized rules should never contain a child selector! BAD - treehead > treerow > treecell { } BEST - .treecell-header { } </li></ul><ul><li>Rely on inheritance! BAD - #bookmarkMenuItem > .menu-left { list-style-image: url(blah); } GOOD - #bookmarkMenuItem { list-style-image: url(blah); } </li></ul>https://developer.mozilla.org/en/Writing_Efficient_CSS
  32. 32. Tools of Analyzing Performance <ul><li>YSlow (YAHOO!) </li></ul><ul><li>http:// developer.yahoo.com/yslow / </li></ul><ul><li>Page Speed (Google) http://code.google.com/speed/page-speed/ </li></ul><ul><li>Firebug </li></ul><ul><li>http://getfirebug.com/ </li></ul><ul><li>Fasterfox </li></ul><ul><li>http:// fasterfox.mozdev.org </li></ul>
  33. 33. Thanks!

×