元素内容的支持,弃用了多种旧方法。
3.3 |
2018年1月19日 |
3.3.1 (2018年1月20日) |
84.8 |
弃用旧函数,函数现在可以接受类,并支持其写成数组格式。 |
替换较低版本jQuery
1.6.2版本的运行次数,远远超过两个老版本。尤其是第一条语句,性能有数倍 的提高。其他语句的测试,比如.attr(“value”)和.val(),如果你还在使用1.4X的版本,建议尽快换掉。
(二)用对选择器
最快的选择器:
id选择器和元素标签选择器
$('#id') // getElementById('id')
$('form')
$('input')
遇到这些选择器的时候, jQuery内部会自动调用 浏览器的原生方法(比如 getElementById(), getElementsByTagName()),所以它们的执行速度快。
较慢的选择器:
class 选择器
$('.className')
Class选择器的性能,取决于不通的浏览器。 Firefox、Safari、 Chrome、Opera浏览器, 都有原生方法 getElementByClassName(),所以速度并不慢。 但是,IE5-IE8都没有部 署这个方法,所以这个选择器在IE中会相当慢。
function getByClassName(obj,cls){
var element = document.getElementsByTagName("*");
var result = [];
for (var i = 0; i < element.length; i++) {
if (element[i].className == cls) {
result.push(element[i]);
}
}
return result;
}
最慢的选择器:
伪类选择器和属性选择器
$(':hiddden')
$('[attribute=value]')
这两种语句是最慢的,因为浏览器没有针对它们的原生方法。但是,一些浏览器的新版本,增加了querySelector()和 querySelectorAll()方法, 因此会使这类选择器的性能有大幅高。
ID选择器遥遥领先,然后是标签选择器,第三是Class选择器,其他选择器都非常慢。
如果你使用的还是IE较低版本的浏览器,一定要尽量规避掉后两者的写法。
(三)理解子元素和父元素的关系
下面六个选择器,都是从父元素中选择子元素。你知道哪个速度最快, 哪个速度最慢吗?
$('.child', $parent)
$parent.find('.child')
$parent.children('.child')
$('#parent > .child')
$('#parent .child')
$('.child', $('#parent'))
一起来看看它的运行远离:
$('.child',$parent)
这条语句的意思是,给定一个DOM对象,然后从中选择一个子元素。jQuery会自动把它转成 $parent.find(‘.child’) 这会导致一定的性能损失。它比最快的形式慢了5%-10%。
$parent.find('.child')
这条是最快的语句。.find()方法会调用浏览器的原生方法(getElementById,getElementByName, getElementByTagName等等),所以速度较快。
$parent.children('.child')
这条语句在jQuery内部,会使用$.sibling()和JavaScript的nextSibling()方法,一个个遍历节点。它比最快的形式大约慢50%。
$('#parent>.child')
jQuery 内部使用Sizzle引擎,处理各种选择器。Sizzle引擎的选择顺序是从右到左,所以这条语句是先选.child,然后再一个个过滤出父元素#parent,这导致它比最快的形式大约慢70%。
$('#parent .child')
这条语句不上一条是同样的情况。但是,上一条叧选择直接的子元素,这一条可以选择多级子元素, 所以它的速度更慢,大概比最快的形式慢了77%。
$('.child',$('#parent'))
jQuery内部会将这条语句转成$(‘#parent’).find(‘.child’),比最快的形式慢了23%。
最佳选择是$parent.find(‘.child’)。而且,由于$parent往往在前面的操作已经生成,jQuery会进行缓存,所以进一步加快了执行速度。
(四)不要过渡使用jQuery
jQuery速度再快,也无法不原生的javascript方法相比。所以有原生方法可以使用的场合,尽量避免使用jQuery。
• 请看下面的例子,为a元素绑定一个处理点击事件的函数:
根据测试,this.id 的速度比 $(this).attr(‘id’) 快了 20 多倍。
更多测试
$(:input[name=i]) //执行时间 = 5353 毫秒
$(input[name=i]) //执行时间 = 661 毫秒
$('#i') //执行时间 = 213 毫秒
document.getElementById("i"); //执行时间 = 9 毫秒(原生js威武)
$('input') //执行时间 = 575 毫秒
document.getElementsByTagName("input"); //执行时间 = 9 毫秒(原生js威武)
$('.class') //执行时间 = 563 毫秒
document.getElementsByTagName("input"); //执行时间 = 5 毫秒 //IE下有不兼容
(五)做好缓存
选中某一个网页元素,是开销很大的步骤。所以,使用选择器的次数应该越少越好,并且尽可能缓存选中的结果,便于以后反复使用。
• 请看下面的例子:
根据测试,缓存比不缓存快了 2-3 倍。
如果你打算在其他函数中使用jQuery对象,那么你可以把它们缓存到全局环境中:
// 在全局范围定义一个对象 (例如: window对象)
window.$my = {
head : $("head"),
traffic_light : $("#traffic_light"),
traffic_button : $("#traffic_button")
};
//你也可以在其他函数中 使用它
function do_something(){
// 现在你可以引用存储的结果并操作它们
var script = document.createElement("script"); $my.head.append(script);
// 当你在函数内部操作是, 可以继续将查询存入全局对象中去. $my.cool_results = $("#some_ul li");
$my.other_results = $("#some_table td");
// 将全局函数作为一个普通的jquery对象去使用. $my.other_results.css("border-color", "red");
$my.traffic_light.css("border-color", "green");
}
(六)使用链式写法
jQuery的一大特点,就是允许使用链式写法,比如:
$('div').find('h3').eq(2).html('Hello');
采用链式写法时,jQuery自动缓存每一步的结果,因此比非链式写法性能更快。
根据测试,链式写法比(丌使用缓存的)非链式写法,大约快了 25% 。
(七)事件的委托处理
- JavaScript的事件模型,采用”冒泡”模式,也就是说,子元素的事件会逐级向上”冒泡”,成为父元素的事件。利用这一点,可以大大简化事件的绑定。
- 比如,有一个表格(table元素),里面有100个格子(td元素),现在要求在每个格子上面绑定一个点击事件(click),请问是否需要将下面的命令执行100次?
叧需要在父元素table上绑定1次即可,而不需要在子元素上绑定100次, 从而大大提高性能。因为td元素发生点击事件之后,这个事件会“冒泡” 到父元素table上面,从而被监听到。
这就叫事件的”委托处理”,也就是子元素”委托”父元素处理这个事件。
• 具体的写法有两种。第一种是采用.delegate()方法,第二种是采用.live()方法,
但是需要注意的是,live()方法在1.7版本之后就废弃了,随之被on()方法所代替,而delegate()方法也在3.0版本中废弃。
所以现在一般会使用on()
$("table").each(function(){
$("td", this).on("click", function(){
$(this).toggleClass("cli√ck"); });
});
(八)少改动DOM结构
改动DOM结构开销很大,因此不要频繁使用.append()、.insertBefore() 和.insetAfter()这样的方法。如果要插入多个元素,就先把它们合并,然后再一次性插入。
• 比如,你想动态的创建一组列表元素,千万不要这样做:
var top_100_list = [...], // 假设这里是100个独一无二的字符串
$mylist = $("#mylist"); // jQuery 选择到 <ul> 元素
for (var i=0, l=top_100_list.length; i<l; i++){
$mylist.append("<li>" + top_100_list[i] + "</li>");
}
• 应该在插入Dom之前合并好:
var top_100_list = [...] ,
$mylist = $("#mylist") ,
top_100_li = "";
for (var i=0, l=top_100_list.length; i<l; i++){
top_100_li += "<li>" + top_100_list[i] + "</li>";
}
$mylist.html( top_100_li );
如果你要对一个DOM元素进行大量处理,应该先用.detach()方法,把这个元素从DOM中取出来,处理完毕以后,再重新插回文档。
var a=$('.level-3').detach();
// 可以进行操作
$('#content').append(a);
与.remove()方法不同的是, 这个方法不会把匹配的元素从jQuery对象中删除,所有绑定的事件、附加的数据等都会保留下来,因而可以在将来再使用这些匹配的元素。
如果你要在DOM元素上储存数据:
根据测试,后一种写法要比前一种写法,快了将近10倍。因为elem.data()方法 是定义在jQuery函数的prototype对象上面的,而$.data()方法是定义jQuery凼 数上面的,调用的时候不从复杂的jQuery对象上调用,所以速度快得多。
(九)正确处理循环
• 循环是一种比较耗时的操作,如果可以使用复杂的选择器直接选中元素, 就不要使用循环,去一个个辨认元素。
• JavaScript原生循环方法for和while,要比jQuery的.each()方法快,应该优先使用原生方法。
假设1024条的数据,使用for和each进行循环,耗时结果如下:
(十)尽量少生成jQuery对象
• 每当你使用一次选择器(比如$(‘#id’)),就会生成一个jQuery对象。
• jQuery对象是一个很庞大的对象,带有很多属性和方法,会占用不少资源。所以,尽量少生成jQuery对象。
• 许多jQuery方法都有两个版本,一个是供jQuery对象使用的版本,另一 个是供jQuery函数使用的版本。
• 比如text()方法,你既可以使用针对jQuery对象的版本,也可以使用针对 jQuery函数的版本: