3. Me.
Interaction Designer at Molecular, Inc.
jQuery Team Member - Dev. Relations
@paul_irish
http://paulirish.com Front-end development blog
http://aurgasm.us Eclectic music blog
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. 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(){});
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. $(‘#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. $(‘#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();
22. Come on, my selector
Selector engines have come a long, long way.
23. Come on, my selector
Selector engines have come a long, long way.
24. Come on, my selector
Engines work in different ways
Top-down, bottom-up, function creation, other crazy shit
// from NWMatcher:
// selecting '.outmost #outer span'
T=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. 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. 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. 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. 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. Selector Optimization
Specific on the right, light on the left
// let's 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. Selector Optimization
Of course, descending from an #id is best
// basic #id-based selector
var arms = $('#container div.robotarm');
// hyper-optimized #id case first, then find:
var arms = $('#container').find('div.robotarm');
31. Selector Optimization
Don’t be needlessly specific
// let's find scott
.data table.attendees td.gonzalez
// better: drop the middle
.data td.gonzalez
A flatter DOM helps, so move to HTML5
Also a wider range of tags speeds up filters
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
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. Event Delegation
live() isn’t just for dynamic content
Speeds up page load
Only one event handler is bound vs many
Good 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. Event Delegation
live() isn’t just for dynamic content
Speeds up page load
Only one event handler is bound vs many
Good 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. 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. Event Delegation new
in
1.4
.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. The DOM is slow
Pull elements off the DOM while you toy with them
var table = $('#some-table');
var parent = table.parent();
table.detach();
table.addLotsAndLotsOfRows();
parent.append(table);
40. The DOM is slow
Pull elements off the DOM while you toy with them
var table = $('#some-table');
var parent = table.parent();
new
table.detach();
in 1
.4
table.addLotsAndLotsOfRows();
parent.append(table);
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');
Timings for X elements
3000
2250 (1000 iterations)
1500 css()
style tag
750
0
1 5 10 20 50
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. 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. 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. 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. Don’t act on absent elements
$.fn.plugin = function(opts){
if(!this.length) return this;
var opts = $.extend(......
...
return this.each(...
54. Variable definition
// old 'n busted // new hotness
var test1 = 1; var test1 = 1,
var test2 = function() { test2 = function() {
// function code // function code
}; },
var test3 = test2(test1); test3 = test2(test1);
55. Munge the primitives
Define shortcuts at the top of your scope
Good for both compression and scope chain traversal
var TRUE = true,
FALSE = false,
NULL = null,
window = self,
undefined = undefined;
56. Munge the primitives
Define shortcuts at the top of your scope
Good for both compression and scope chain traversal
var TRUE = true,
FALSE = false,
NULL = null,
window = self,
undefined;
undefined = undefined;
58. var str=‘Let’s put this into action’
// 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. var str=‘Let’s put this into action’
// 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. // html.no-js ==> html.js
var elem = document.getElementsByTagName('html')[0];
var str=‘Let’s put this into action’
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/,
'js')})(document.documentElement);
// pass className, object string notation
(function(H,C){H[C]=H[C].replace(/bno-jsb/,'js')})
(document.documentElement,'className')
61. Conditionals
// old 'n busted
if ( type === 'foo' || type === 'bar' ) {}
// regex test
if ( /^(foo|bar)$/.test(type) ) {}
// obj literal lookup (smaller if <5 items)
if ( ({foo:1,bar:1})[type] ) {}
62. Logic and Ternary operands
// basic function detection
document.querySelectorAll && document.querySelectorAll('a:nth-child(2)')
// assignment is legal, but it evaluates to the right expression
callback && (isCallbackCalled = true) && callback(returnVal);
// call or cache the callback function
(isCallbackCalled || returnVal) ? fn(returnVal) : (callback = fn);
// inline function calls
isToday('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. 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. Comments
/*!
* Will not be removed by YUI Compressor
*/
// for quick toggling on and off:
/* */
aaaahYeah();
/* */
/* * /
ohHellNo();
/* */
66. Thanks, ya’ll.
Slides at http://paulirish.com/perf
@paul_irish
thx:
Alex Sexton, Ben Alman, Adam Sontag,
James Padolsey, temp01, #jquery on Freenode
67. todo
shadow effect to code samples
more 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. `
// 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()
Editor's Notes
update the taskspeed shit.
delegation facts.
i hang in #jquery so a lot of examples are from real code discussed there.
like copypasting a line or three of code
rebecca murphey will be discussing this technique a lot more
the convenience of context will incur the cost of three extra if() statements in jQuery.fn.init()
selectors. ugh.
did it because i wanted to study.
the old ones are probablyw ayyyyy easier to study as the new ones use some crazy techniques
did it because i wanted to study.
the old ones are probablyw ayyyyy easier to study as the new ones use some crazy techniques
before sizzle it was LTR. sizzle changed it.
before sizzle it was LTR. sizzle changed it.
before sizzle it was LTR. sizzle changed it.
be brief on the left
the more you can filter down the righthandmost expression, the faster it will run.
id is grabbed. optimization
in my testing it didnt speed up basic selecting.
css engine too.
TDs and LI&#x2019;s etccc
document.body as an append target is WIN
padolsey&#x2019;s research on animate()
strings take up a lot of space, so allowing them to be munged helps a lot
compress it and look for repetition