不要每次都在循环中访问数组的 length 属性,应在循环开始之前就将其缓存:
var myLength = myArray.length; for (var i = 0; i < myLength; i++) { // do stuff }
在循环外执行 append 操作
直接操作 DOM 是非常耗费性能的,尤其不要在循环中直接操作 DOM:
// 这样性能很差 $.each(myArray, function(i, item) { var newListItem = '<li>' + item + '</li>'; $('#ballers').append(newListItem); });
// 这样性能较好
var frag = document.createDocumentFragment();
$.each(myArray, function(i, item) {
var newListItem = '<li>' + item + '</li>';
frag.appendChild(newListItem);
});
$('#ballers')[0].appendChild(frag);
// 这样也很好
var myHtml = '';
$.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() { // ... }); }); // 好 var PI = { 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 选择器:
// 快 $('#container div.robotarm'); // 相当快 $('#container').find('div.robotarm'); 使用 $.fn.find 的方式更快,因为在 $.fn.find 之前的选择器并没有使用 jQuery 自带的 Sizzle 选择器引擎,而是使用了浏览器 document.getElementById() 方法,浏览器原生的方法自然更快。 使用组合选择器时,尽可能使右端更明确,而左端不尽量不明确: // 未优化 $('div.data .gonzalez'); // 已优化 $('.data td.gonzalez');
尽量在选择器右端使用 tag.class,而左端尽可能只使用 tag 或者 .class。
避免过度具体:
$('.data table.attendees td.gonzalez'); // 在不影响结果的情况下尽量删掉中间多余部分 $('.data td.gonzalez');
简洁的 DOM 结构也有助于提升选择器的性能,因为选择器可能少走几层弯路去寻找那些元素。
尽量避免使用通配符,任何显式或隐式的使用通配符,都会降低选择器的性能:
$('.buttons > *'); // 极慢 $('.buttons').children(); // 好多了 $('.gender :radio'); // 隐式地使用通配符,慢 $('.gender *:radio'); // 显式地使用通配符,同上,慢 $('.gender input: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%。