jQuery Anti-Patterns forPerformance &CompressionPaul IrishNC JavaScript Camp ’10
jQuery Anti-Patterns forPerformance &CompressionPaul IrishNC JavaScript Camp ’10
Me.Interaction Designer at Molecular, Inc.jQuery Team Member - Dev. Relations     @paul_irishhttp://paulirish.com Front-en...
Performance
Performance
wassup shawty? how u doin’                  Taskspeed Test Lines of Code20015010050 0      YUI   Dojo 1.3.1 Dojo 1.2.3 Qoo...
Oft cited best practices Cache length during loops Cache your selections Leverage documentFragment Append new content outs...
Oft cited best practices Cache length during loops// appending inside. bad.$.each(reallyLongArray, function(count, item) {...
var newLI = <li> + item + </li>;      $(#ballers).append(newLI);});Oft cited best practices// documentFragment off-DOMvar ...
Keep things DRY If you’re repeating yourself, you’re doing it wrong
Moar DRY plz?if ($ventfade.data(currently) != showing) {  $ventfade.stop();}if ($venthover.data(currently) != showing) {  ...
All clean! Thxvar elems = [$ventfade,$venthover,$spans];$.each(elems,function(k,v){    if (v.data(currently) != showing){ ...
Architecture Anti-Patterns Anonymous functions bound everywhere suck$(document).ready(function(){    ...    $(#magic).clic...
Architecture - Object Literalvar PI = {  onReady   : function(){      ...      $(#magic).click(PI.candyMtn);      $(#happi...
Architecture - Object Literal Advantages:  Easier to navigate and discuss  Profilers give you actual names to work with  Y...
Anti-Pattern: The requery// create and append your element$(document.body).append("<div class=baaron/>");// requery to bin...
$(‘#whats .the’,context)
This is not the .context property  // find all stylesheets in the body  var bodySheets = $(style,document.body);  bodyShee...
$(‘#whats .the’,context) Never pass it a selector string. Ever. No performance gain vs $(root).find(selector)   var arms =...
$(‘#whats .the’,context) You typically pass it this, but it’s purely a convenience to avoid find() $(form.comments,this).s...
The Crowd Say Bo Selector
Come on, my selectorSelector engines have come a long, long way.
Come on, my selectorSelector engines have come a long, long way.
Come on, my selectorEngines work in different waysTop-down, bottom-up, function creation, other crazy shit// from NWMatche...
Selector engines, parse direction Left to right (Top-down)      Right to left (Bottom-up)        Mootools                 ...
Selector engines, parse direction  div.data table.attendees .gonzalez Left to right (Top-down)      Right to left (Bottom-...
Selector engines, parse direction Left to right (Top-down)      Right to left (Bottom-up)        Mootools                 ...
Selector engines, parse direction Left to right (Top-down)      Right to left (Bottom-up)        Mootools                 ...
Selector Optimization Specific on the right, light on the left // lets find scott div.data .gonzalez // specific on right,...
Selector Optimization Of course, descending from an #id is best// basic #id-based selectorvar arms = $(#container div.robo...
Selector Optimization Don’t be needlessly specific // lets find scott .data table.attendees td.gonzalez // better: drop th...
Selector Optimization Avoid the universal selector Avoid the implied universal selector $(.buttons > *) // terribly costly...
Selector Optimization Google PageSpeed’s efficient selectors analysis MDC: Writing Efficient CSS  https://developer.mozill...
Event Delegation function delegate(type, delegate, handler) {     return $(document).bind(type, function(event) {         ...
Event Delegationlive() isn’t just for dynamic contentSpeeds up page load  Only one event handler is bound vs manyGood for ...
Event Delegationlive() isn’t just for dynamic contentSpeeds up page load  Only one event handler is bound vs manyGood for ...
Event Delegation   delegate() bakes in huge performance gains   explicit context reduces overhead by ~80%   Use it instead...
Event Delegation                               new                                                1.4     in              ...
The DOM is slowPull elements off the DOM while you toy with themvar table = $(#some-table);var parent = table.parent();tab...
The DOM is slowPull elements off the DOM while you toy with themvar table = $(#some-table);var parent = table.parent();   ...
Minimize DOM touches       Use classes, but if a style change user-selected:  jQuery(a.swedberg).css(color, #BADA55);  jQu...
Minimize DOM touches
Don’t treat jQuery as a Black Box Use the source as your documentation Add this to your bookmark bar, NOW!   http://ajax.g...
Don’t treat jQuery as a Black Box Learn the lesser-known methods   map(), slice(), stop(), (de)queue(),   prevAll(), pushS...
Don’t act on absent elements jQuery is very kind and doesn’t throw errors at you Don’t assume it’s just fine to do   $(#do...
Don’t act on absent elements jQuery.fn.doOnce = function(func){     this.length && func.apply(this);     return this; } $(...
Don’t act on absent elements $.fn.plugin = function(opts){    if(!this.length) return this;    var opts = $.extend(...... ...
Setter Methodsview-source:setters.js
newNew Element Creation                        1.4                                                !                       ...
neweq(), first(), last()                1.4                                         !                                     ...
Data()// regular:$(elem).data(key,value);// omg like 10x faster:$.data(elem,key,value);
Compression
CompressionYUI Compressor  Sits on Rhino.Comments, whitespace, variable replacement//it already does these micro-optimizat...
Variable definition// old n busted            // new hotnessvar test1 = 1;              var test1 = 1,var test2 = function...
Munge the primitivesDefine shortcuts at the top of your scope  Good for both compression and scope chain traversalvar TRUE...
Munge the primitivesDefine shortcuts at the top of your scope  Good for both compression and scope chain traversalvar TRUE...
Munge the primitives(function(){   var window = this, document = document,undefined;   /* code */})();(function(window, do...
var str=‘Let’s put this intoaction’ // html.no-js html> <!doctype ==> html.js var elem = document.getElementsByTagName(htm...
var str=‘Let’s put this intoaction’ // html.no-js ==> html.js var elem = document.getElementsByTagName(html)[0]; elem.clas...
// html.no-js ==> html.jsvar str=‘Let’s put this intovar elem = document.getElementsByTagName(html)[0];elem.className = el...
Conditionals// old n bustedif ( type === foo || type === bar ) {}// regex testif ( /^(foo|bar)$/.test(type) ) {}// obj lit...
Logic and Ternary operands// basic function detectiondocument.querySelectorAll && document.querySelectorAll(a:nth-child(2)...
Write maintainable code                   As a developer,       you should work first   and foremost            for the use...
Comments/*! * Will not be removed by YUI Compressor */// for quick toggling on and off:/* */ aaaahYeah();/* *//* * / ohHel...
Compression ToolsCompressorRater  http://compressorrater.thruhere.net/YUI Compressor front-end  http://refresh-sf.com/yui/
Thanks, ya’ll. Slides at http://paulirish.com/perf      @paul_irishthx: Alex Sexton, Ben Alman, Adam Sontag, James Padolse...
todoshadow effect to code samplesmore context research and this: http://groups.google.com/group/jquery-dev/msg/b4b7935a401...
`    // pngfix for IE6    // e.g. FL.pngfix(img.bigProdShot,a.thumb);    pngfix : function(sel){      // conditional comme...
Upcoming SlideShare
Loading in...5
×

jQuery Anti-Patterns for Performance

1,522

Published on

jQuery Anti-Patterns for Performance

Published in: Education
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,522
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
42
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide
  • update the taskspeed shit.\ndelegation facts.\n
  • i hang in #jquery so a lot of examples are from real code discussed there.\n
  • \n
  • \n
  • \n
  • \n
  • like copypasting a line or three of code\n
  • \n
  • \n
  • \n
  • rebecca murphey will be discussing this technique a lot more\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • the convenience of context will incur the cost of three extra if() statements in jQuery.fn.init()\n
  • \n
  • selectors. ugh.\n
  • did it because i wanted to study.\nthe old ones are probablyw ayyyyy easier to study as the new ones use some crazy techniques\n
  • did it because i wanted to study.\nthe old ones are probablyw ayyyyy easier to study as the new ones use some crazy techniques\n
  • \n
  • before sizzle it was LTR. sizzle changed it.\n
  • before sizzle it was LTR. sizzle changed it.\n
  • before sizzle it was LTR. sizzle changed it.\n
  • be brief on the left\nthe more you can filter down the righthandmost expression, the faster it will run.\n
  • id is grabbed. optimization\n
  • in my testing it didnt speed up basic selecting.\n
  • \n
  • css engine too.\n
  • \n
  • TDs and LI&amp;#x2019;s etccc\n
  • \n
  • \n
  • \n
  • \n
  • document.body as an append target is WIN\n
  • \n
  • \n
  • padolsey&amp;#x2019;s research on animate()\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • strings take up a lot of space, so allowing them to be munged helps a lot\ncompress it and look for repetition\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • DRY obviously\n
  • DRY obviously\n
  • \n
  • really understand truthy and falsy ness\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Transcript of "jQuery Anti-Patterns for Performance"

    1. 1. jQuery Anti-Patterns forPerformance &CompressionPaul IrishNC JavaScript Camp ’10
    2. 2. jQuery Anti-Patterns forPerformance &CompressionPaul IrishNC JavaScript Camp ’10
    3. 3. Me.Interaction Designer at Molecular, Inc.jQuery Team Member - Dev. Relations @paul_irishhttp://paulirish.com Front-end development bloghttp://aurgasm.us Eclectic music blog
    4. 4. Performance
    5. 5. Performance
    6. 6. wassup shawty? how u doin’ Taskspeed Test Lines of Code20015010050 0 YUI Dojo 1.3.1 Dojo 1.2.3 Qooxdoo MooTools Prototype.js jQuery PureDOM
    7. 7. Oft cited best practices Cache length during loops Cache your selections Leverage documentFragment Append new content outside the loop
    8. 8. Oft cited best practices Cache length during loops// appending inside. bad.$.each(reallyLongArray, function(count, item) { Cache your selections var newLI = <li> + item + </li>; Leverage documentFragment $(#ballers).append(newLI);}); Append new content outside the loop// documentFragment off-DOMvar frag = document.createDocumentFragment();$.each(reallyLongArray, function(count, item) { var newLI = <li> + item + </li>; frag.appendChild(newLI[0]);});$(#ballers)[0].appendChild(frag);
    9. 9. var newLI = <li> + item + </li>; $(#ballers).append(newLI);});Oft cited best practices// documentFragment off-DOMvar frag = document.createDocumentFragment(); Cache length during loops$.each(reallyLongArray, function(count, item) { var newLI = <li> + item + </li>; Cache your selections frag.appendChild(newLI[0]);}); Leverage documentFragment$(#ballers)[0].appendChild(frag); Append new content outside the loop// string concatenate and set innerHTMLvar myhtml = ;$.each(reallyLongArray, function(count, item) { myhtml += <li> + item + </li>;});$(#ballers).html(myhtml);
    10. 10. Keep things DRY If you’re repeating yourself, you’re doing it wrong
    11. 11. Moar DRY plz?if ($ventfade.data(currently) != showing) { $ventfade.stop();}if ($venthover.data(currently) != showing) { $venthover.stop();}if ($spans.data(currently) != showing) { $spans.stop();} from http://mt-ventures.com/_js/global.js
    12. 12. All clean! Thxvar elems = [$ventfade,$venthover,$spans];$.each(elems,function(k,v){ if (v.data(currently) != showing){ v.stop(); }})
    13. 13. Architecture Anti-Patterns Anonymous functions bound everywhere suck$(document).ready(function(){ ... $(#magic).click(function(e){ $(#yayeffects).slideUp(function(){ ... }); }); $(#happiness).load(url+ #unicorns,function(){ ... })});
    14. 14. Architecture - Object Literalvar PI = { onReady : function(){ ... $(#magic).click(PI.candyMtn); $(#happiness).load(url+ #unicorns,PI.unicornCb); }, candyMtn : function(e){ $(#yayeffects).slideUp(PI.slideCb); }, slideCb : function(){ ... }, unicornCb : function(){ ... }}$(document).ready(PI.onReady);
    15. 15. Architecture - Object Literal Advantages: Easier to navigate and discuss Profilers give you actual names to work with You can execute these from firebug console You can write unit tests against them
    16. 16. Anti-Pattern: The requery// create and append your element$(document.body).append("<div class=baaron/>");// requery to bind stuff$("div.baaron").click(function(){});// better:// swap to appendTo to hold your elem$("<div class=baaron/>") .appendTo(document.body) .click(function(){});
    17. 17. $(‘#whats .the’,context)
    18. 18. This is not the .context property // find all stylesheets in the body var bodySheets = $(style,document.body); bodySheets.context // ==> BODY element Ignore that for the moment, I know no one that’s found a use
    19. 19. $(‘#whats .the’,context) Never pass it a selector string. Ever. No performance gain vs $(root).find(selector) var arms = $(div.robotarm, #container); // instead do: var arms = $(#container).find(div.robotarm);
    20. 20. $(‘#whats .the’,context) You typically pass it this, but it’s purely a convenience to avoid find() $(form.comments,this).submit(captureSubmit); // exact same as $(this).find(form.comments).submit(captureSubmit); Which is more readable?$(.reply_form, $(this).closest(.comment)).hide();$(this).closest(.comment).find(.reply_form).hide();
    21. 21. The Crowd Say Bo Selector
    22. 22. Come on, my selectorSelector engines have come a long, long way.
    23. 23. Come on, my selectorSelector engines have come a long, long way.
    24. 24. Come on, my selectorEngines work in different waysTop-down, bottom-up, function creation, other crazy shit// from NWMatcher:// selecting .outmost #outer spanT=e.nodeName;if(T=="SPAN"||T=="span"){while((e=e.parentNode)&&e.nodeType==1){if((n=e.getAttributeNode("id"))&&n.value=="outer"){if((e=e.parentNode)&&e.nodeType==1){C=e.className;if(C&&(" "+C+" ").indexOf(" outmost ")>-1){r[X++]=N;continue main;}}}}}
    25. 25. Selector engines, parse direction Left to right (Top-down) Right to left (Bottom-up) Mootools Sizzle Sly YUI 3 Peppy NWMatcher Dojo Acme Ext JS Prototype.js details: http://alexsexton.com/selectors/
    26. 26. Selector engines, parse direction div.data table.attendees .gonzalez Left to right (Top-down) Right to left (Bottom-up) Mootools Sizzle Sly YUI 3 Peppy NWMatcher Dojo Acme Ext JS Prototype.js details: http://alexsexton.com/selectors/
    27. 27. Selector engines, parse direction Left to right (Top-down) Right to left (Bottom-up) Mootools Sizzle Sly YUI 3 Peppy NWMatcher Dojo Acme Ext JS Prototype.js details: http://alexsexton.com/selectors/
    28. 28. Selector engines, parse direction Left to right (Top-down) Right to left (Bottom-up) Mootools Sizzle Sly YUI 3 Peppy NWMatcher Dojo Acme querySelectorAll (qSA) Ext JS Prototype.js details: http://alexsexton.com/selectors/
    29. 29. Selector Optimization Specific on the right, light on the left // lets find scott div.data .gonzalez // specific on right, light on the left .data td.gonzalez tag.class if possible on your right-most selector. just tag or just .class on left.
    30. 30. Selector Optimization Of course, descending from an #id is best// basic #id-based selectorvar arms = $(#container div.robotarm);// hyper-optimized #id case first, then find:var arms = $(#container).find(div.robotarm);
    31. 31. Selector Optimization Don’t be needlessly specific // lets find scott .data table.attendees td.gonzalez // better: drop the middle .data td.gonzalezA flatter DOM helps, so move to HTML5 Also a wider range of tags speeds up filters
    32. 32. Selector Optimization Avoid the universal selector Avoid the implied universal selector $(.buttons > *) // terribly costly $(.buttons).children() // much better $(.gender :radio) // implied universal $(.gender *:radio) // exact same, explicit now $(.gender input:radio) // much better
    33. 33. Selector Optimization Google PageSpeed’s efficient selectors analysis MDC: Writing Efficient CSS https://developer.mozilla.org/en/Writing_Efficient_CSS Benchmark.js http://code.paulirish.com/sandbox/benchmark.js
    34. 34. Event Delegation function delegate(type, delegate, handler) { return $(document).bind(type, function(event) { var target = $(event.target); if (target.is(delegate)) { return handler.apply(target, arguments); } }); } delegate(click,td.jehl,createRockstar); // and with live(): $(td.jehl).live(click,createRockstar);
    35. 35. Event Delegationlive() isn’t just for dynamic contentSpeeds up page load Only one event handler is bound vs manyGood for >3 elements all getting the same handler // using live(), skipping selection on load var jqElem = $(document); jqElem.selector = li.ui; jqElem.live(dblclick, dblhandler);
    36. 36. Event Delegationlive() isn’t just for dynamic contentSpeeds up page load Only one event handler is bound vs manyGood for >3 elements all getting the same handler // using live(), skipping selection on load var jqElem = $(document); jqElem.selector = li.ui; jqElem.live(dblclick, dblhandler);
    37. 37. Event Delegation delegate() bakes in huge performance gains explicit context reduces overhead by ~80% Use it instead of live() if possible// awkward but equivalent$(a.trigger,$(#container)[0]).live(click,handlerFn)// so damn fine$(#container).delegate(click,a.trigger,handlerFn)
    38. 38. Event Delegation new 1.4 in .2! delegate() bakes in huge performance gains explicit context reduces overhead by ~80% Use it instead of live() if possible// awkward but equivalent$(a.trigger,$(#container)[0]).live(click,handlerFn)// so damn fine$(#container).delegate(click,a.trigger,handlerFn)
    39. 39. The DOM is slowPull elements off the DOM while you toy with themvar table = $(#some-table);var parent = table.parent();table.detach();table.addLotsAndLotsOfRows();parent.append(table);
    40. 40. The DOM is slowPull elements off the DOM while you toy with themvar table = $(#some-table);var parent = table.parent(); newtable.detach(); in 1 .4table.addLotsAndLotsOfRows();parent.append(table);
    41. 41. Minimize DOM touches Use classes, but if a style change user-selected: jQuery(a.swedberg).css(color, #BADA55); jQuery(<style type="text/css"> a.swedberg { color: BADA55; } </style>) .appendTo(head);3000 Timings for X elements2250 (1000 iterations)1500 css() style tag750 0 1 5 10 20 50
    42. 42. Minimize DOM touches
    43. 43. Don’t treat jQuery as a Black Box Use the source as your documentation Add this to your bookmark bar, NOW! http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js http://bit.ly/jqsource Determine which are convenience methods: getScript: function( url, callback ) { return jQuery.get(url, null, callback, "script"); }, getJSON: function( url, data, callback ) { return jQuery.get(url, data, callback, "json"); },
    44. 44. Don’t treat jQuery as a Black Box Learn the lesser-known methods map(), slice(), stop(), (de)queue(), prevAll(), pushStack(), inArray() , etc // index() in jQuery <= 1.3.2 $(#rdworth).parent().children().index( $(#rdworth)[0] ) // using prevAll() is 10% faster (also sexier) $(#rdworth).prevAll().length // in jQuery 1.4 $(#rdworth).index()
    45. 45. Don’t act on absent elements jQuery is very kind and doesn’t throw errors at you Don’t assume it’s just fine to do $(#doesntexist).slideUp() // this will execute genFx(), speed() and animate() // before it hits an each() jQuery UI widgets have a lot of overhead you’ll hit
    46. 46. Don’t act on absent elements jQuery.fn.doOnce = function(func){ this.length && func.apply(this); return this; } $(li.cartitems).doOnce(function(){ // make it ajax! o/ });
    47. 47. Don’t act on absent elements $.fn.plugin = function(opts){ if(!this.length) return this; var opts = $.extend(...... ... return this.each(...
    48. 48. Setter Methodsview-source:setters.js
    49. 49. newNew Element Creation 1.4 ! injQuery("<div/>", { id: "foo", rel : "something" css: { height: "50px", width: "50px", color: "blue", backgroundColor: "#ccc" }, click: function() { $(this).css("backgroundColor", "red"); }}).appendTo("body");
    50. 50. neweq(), first(), last() 1.4 ! invar lastelem = $elems.eq(-1); // get() too!$(#nav li:first) === $(#nav li).first()$(#nav li:last) === $(#nav li).last()
    51. 51. Data()// regular:$(elem).data(key,value);// omg like 10x faster:$.data(elem,key,value);
    52. 52. Compression
    53. 53. CompressionYUI Compressor Sits on Rhino.Comments, whitespace, variable replacement//it already does these micro-optimizations:object[prop] ==> object.prop{key:123} ==> {key:123}jons apostophes ==> "jons apostrophes"bigass + string ==> bigass string
    54. 54. Variable definition// old n busted // new hotnessvar test1 = 1; var test1 = 1,var test2 = function() { test2 = function() { // function code // function code}; },var test3 = test2(test1); test3 = test2(test1);
    55. 55. Munge the primitivesDefine shortcuts at the top of your scope Good for both compression and scope chain traversalvar TRUE = true, FALSE = false, NULL = null, window = self, undefined = undefined;
    56. 56. Munge the primitivesDefine shortcuts at the top of your scope Good for both compression and scope chain traversalvar TRUE = true, FALSE = false, NULL = null, window = self, undefined; undefined = undefined;
    57. 57. Munge the primitives(function(){ var window = this, document = document,undefined; /* code */})();(function(window, document, undefined){ /* code */})(this,this.document);
    58. 58. var str=‘Let’s put this intoaction’ // html.no-js html> <!doctype ==> html.js var elem = document.getElementsByTagName(html)[0]; elem.className = elem.className.replace(no-js,js); <html class="no-js"> // quicker reference, safer replace <head> var elem = document.documentElement; elem.className = elem.className.replace(/bno-jsb/,js); <script> // one// change the html class to js line ftw! // in the head, no FOUC document.documentElement.className = document.documentElement.className.replace(/bno-jsb/, </script> js); </body> // shorter with a self-executing anonymous function (function(B){B.className=B.className.replace(/bno-jsb/,
    59. 59. var str=‘Let’s put this intoaction’ // html.no-js ==> html.js var elem = document.getElementsByTagName(html)[0]; elem.className = elem.className.replace(no-js,js); // quicker reference, safer replace var elem = document.documentElement; elem.className = elem.className.replace(/bno-jsb/,js); // one line ftw! document.documentElement.className = document.documentElement.className.replace(/bno-jsb/, js); // shorter with a self-executing anonymous function (function(B){B.className=B.className.replace(/bno-jsb/,
    60. 60. // html.no-js ==> html.jsvar str=‘Let’s put this intovar elem = document.getElementsByTagName(html)[0];elem.className = elem.className.replace(no-js,js);action’// quicker reference, safer replacevar elem = document.documentElement;elem.className = elem.className.replace(/bno-jsb/,js);// one line ftw!document.documentElement.className =document.documentElement.className.replace(/bno-jsb/,js);// shorter with a self-executing anonymous function(function(B){B.className=B.className.replace(/bno-jsb/,js)})(document.documentElement);// pass className, object string notation(function(H,C){H[C]=H[C].replace(/bno-jsb/,js)})(document.documentElement,className)
    61. 61. Conditionals// old n bustedif ( type === foo || type === bar ) {}// regex testif ( /^(foo|bar)$/.test(type) ) {}// obj literal lookup (smaller if <5 items)if ( ({foo:1,bar:1})[type] ) {}
    62. 62. Logic and Ternary operands// basic function detectiondocument.querySelectorAll && document.querySelectorAll(a:nth-child(2))// assignment is legal, but it evaluates to the right expressioncallback && (isCallbackCalled = true) && callback(returnVal);// call or cache the callback function(isCallbackCalled || returnVal) ? fn(returnVal) : (callback = fn);// inline function callsisToday(Saturday) && Math.round(Math.random()) && $(#winnar).show()// if JSON2.js or Native JSON is present, otherwise eval.data = window.JSON && JSON.parse(data) || eval((+data +));
    63. 63. Write maintainable code As a developer, you should work first and foremost for the user of your products. The second most important person to work for is the developer that takes over from you. - Christian Heilmann
    64. 64. Comments/*! * Will not be removed by YUI Compressor */// for quick toggling on and off:/* */ aaaahYeah();/* *//* * / ohHellNo();/* */
    65. 65. Compression ToolsCompressorRater http://compressorrater.thruhere.net/YUI Compressor front-end http://refresh-sf.com/yui/
    66. 66. Thanks, ya’ll. Slides at http://paulirish.com/perf @paul_irishthx: Alex Sexton, Ben Alman, Adam Sontag, James Padolsey, temp01, #jquery on Freenode
    67. 67. todoshadow effect to code samplesmore context research and this: http://groups.google.com/group/jquery-dev/msg/b4b7935a4013dfe7 and http://ispeakwebstuff.co.uk/web-design-development-tutorials/clever-jquery-selectors/
    68. 68. ` // pngfix for IE6 // e.g. FL.pngfix(img.bigProdShot,a.thumb); pngfix : function(sel){ // conditional comments for inclusion of that js. if (typeof DD_belatedPNG == undefined){ return; } else { // delay pngfix until window onload $(window).load(function(){ $(sel).each(function() { DD_belatedPNG.fixPng(arguments[1]); }); }); } } // end of FL.pngfix()
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×