对于jQuery性能的一些优化建议
不要每次都在循环中访问数组的length属性,应在循环开始之前就将其缓存:
varmyLength=myArray.length;
for(vari=0;i<myLength;i++){
//dostuff
}
在循环外执行append操作
直接操作DOM是非常耗费性能的,尤其不要在循环中直接操作DOM:
//这样性能很差
$.each(myArray,function(i,item){
varnewListItem='<li>'+item+'</li>';
$('#ballers').append(newListItem);
});
//这样性能较好
varfrag=document.createDocumentFragment();
$.each(myArray,function(i,item){
varnewListItem='<li>'+item+'</li>';
frag.appendChild(newListItem);
});
$('#ballers')[0].appendChild(frag);
//这样也很好
varmyHtml='';
$.each(myArray,function(i,item){
html+='<li>'+item+'</li>';
});
$('#ballers').html(myHtml);
代码要保持精炼
避免做重复的事情。如果你一直在做重复的事情,那么就可能出问题了:
//丑
if($eventfade.data('currently')!='showing'){
$eventfade.stop();
}
if($eventhover.data('currently')!='showing'){
$eventhover.stop();
}
if($spans.data('currently')!='showing'){
$spans.stop();
}
//漂亮!!
var$elems=[$eventfade,$eventhover,$spans];
$.each($elems,function(i,elem){
if(elem.data('currently')!='showing'){
elem.stop();
}
});
警惕匿名函数
匿名函数满天飞是很痛苦的事情,它们难以调试、维护、测试或者复用,应尽可能的对函数命名并将其封装在对象中,实施有效的管理:
//不好
$(document).ready(function(){
$('#magic').click(function(e){
$('#yayeffects').slideUp(function(){
//...
});
});
$('#happiness').load(url+'#unicorns',function(){
//...
});
});
//好
varPI={
onReady:function(){
$('#magic').click(PI.candyMtn);
$('#happiness').load(PI.url+'#unicorns',PI.unicornCb);
},
candyMtn:function(e){
$('#yayeffects').slideUp(PI.slideCb);
},
slideCb:function(){...},
unicornCb:function(){...}
};
$(document).ready(PI.onReady);
选择器的优化
随着越来越多的浏览器支持document.querySelectorAll(),选择器的重担已经慢慢转移给浏览器了,但还是有一些技巧需要注意:
优先并尽可能地使用ID选择器:
//快
$('#containerdiv.robotarm');
//相当快
$('#container').find('div.robotarm');
使用$.fn.find的方式更快,因为在$.fn.find之前的选择器并没有使用jQuery自带的Sizzle选择器引擎,而是使用了浏览器document.getElementById()方法,浏览器原生的方法自然更快。
使用组合选择器时,尽可能使右端更明确,而左端不尽量不明确:
//未优化
$('div.data.gonzalez');
//已优化
$('.datatd.gonzalez');
尽量在选择器右端使用tag.class,而左端尽可能只使用tag或者.class。
避免过度具体:
$('.datatable.attendeestd.gonzalez');
//在不影响结果的情况下尽量删掉中间多余部分
$('.datatd.gonzalez');
简洁的DOM结构也有助于提升选择器的性能,因为选择器可能少走几层弯路去寻找那些元素。
尽量避免使用通配符,任何显式或隐式的使用通配符,都会降低选择器的性能:
$('.buttons>*');//极慢
$('.buttons').children();//好多了
$('.gender:radio');//隐式地使用通配符,慢
$('.gender*:radio');//显式地使用通配符,同上,慢
$('.genderinput:radio');//嗯,快多了
使用事件代理
事件代理允许将一个事件绑定到某个容器上(例如一个无序列表ul),而不是绑定到容器内所有元素上(例如列表元素li)。虽说$.fn.live和$.fn.delegate都是将事件绑定到容器上,但是应尽可能是用$.fn.delegate,毕竟其明确的上下文(相较于$.fn.live的上下文是document)要小得多,避免了很多不必要的过滤。
除了性能方面的提升,如果给绑定了事件的容器内添加新元素,那么这些新元素就无须再次绑定事件了,这也是个优点。
//不好(如果列表元素非常多,你就悲剧了)
$('li.trigger').click(handlerFn);
//好些:使用$.fn.live进行事件代理
$('li.trigger').live('click',handlerFn);
//最好:使用$.fn.delegate进行事件代理
//因为这样可以明确的指定一个上下文
$('#myList').delegate('li.trigger','click',handlerFn);
将元素从DOM卸载出来再操作
DOM操作是比较慢的,所以应尽量避免直接操作DOM。jQuery在其1.4版中引入了$.fn.detach方法,可以将元素从DOM中卸载出来然后进行操作,操作好了之后再添加到DOM中:
var$table=$('#myTable');
var$parent=$table.parent();
$table.detach();
//...例如这里给表格添加了很多很多行
$parent.append(table);
使用外部样式表为大量元素修改样式
当使用$.fn.css为超过20个元素修改样式时,应考虑直接在页面中添加style标签,据说性能可提升60%。
//当元素少于20个时使用这个方法,多余20个时,速度就慢了
$('a.swedberg').css('color','#asd123');
//多余20个元素时,应考虑直接在页面中添加style标签
$('<styletype="text/css">a.swedberg{color:#asd123}</style>')
.appendTo('head');
使用$.data替代$.fn.data
将$.data应用于DOM元素上,比直接在选择器上调用$.fn.data要快10倍。当然,前提是要先明白DOM元素和jQuery结果集之间的区别。
//速度一般 $(elem).data(key,value); //速度提升10倍 $.data(elem,key,value);
别在空元素上浪费时间
jQuery不会主动告诉你,你正在一个空白的结果集上运行代码–而且执行过程中并未出错。所以有时候再执行代码之前,需要先判断一下结果集是否为空:
//不好:执行了三个函数之后
//才发现结果集上没有任何元素
$('#nosuchthing').slideUp();
//好
var$mySelection=$('#nosuchthing');
if($mySelection.length){$mySelection.slideUp();}
//最好:增加一个doOnce插件
jQuery.fn.doOnce=function(func){
this.length&&func.apply(this);
returnthis;
}
$('li.cartitems').doOnce(function(){
//这里可以确保结果集不是空的
});
这种方法特别适用于jQueryUI方面,因为即使结果集中不包含任何元素,其开销也会很大。
变量的定义
可以在一条语句中定义多个变量:
//老掉牙的写法
vartest=1;
vartest2=function(){...};
vartest3=test2(test);
//新写法
vartest=1,
test2=function(){...},
test3=test2(test);
在自执行函数中,变量甚至可以不用定义:
(function(foo,bar){...})(1,2);
条件判断
//土方法
if(type=='foo'||type=='bar'){...}
//较先进的方法
if(/^(foo|bar)$/.test(type)){...}
//使用对象查找
if(({foo:1,bar:1})[type]){...}