jQuery作为一个JavaScript非常优秀的库
是我们在学习前端过程中必学的
虽然它的流行程度已经没有那么巅峰了
但是学习了它对我们学习理解其他库以及框架来说很有帮助
今天第一次写jQuery的相关文章,就先把这个性能问题拿出来
因为大家把时间都用在jQuery语法上了,对这个库的性能优化不是很了解
下面我来给大家总结一下jQuery常用的性能优化
1.选择器使用
jQuery提供了很多方便的选择器语法,介绍几个常用的及它们的性能排名
- id选择器 $(‘#id’)
毫无疑问是最佳性能,因为它底层就直接使用了document.getElementById()
所以提高性能可以从有id的元素往下查找,从而缩小查找范围,e.g. $(‘#wrapper’).find(‘div’); - 标签选择器 $(‘tag’)
同样性能不错,底层直接调用document.getElementByTagName() ,同样因为浏览器兼容性好 - class选择器 $(‘.class’)
之所以它性能没有id和标签选择器好,就是应为让人头疼的IE8及低版本没有,没有的话就只能靠DOM搜索 - 属性选择器 $(‘[attribute=value]’)
这个现代浏览器使用querySelectorAll(),旧的就得使用DOM搜索来达到目的了,性能不理想 -
伪选择器 $(‘:animated’)
我们经常使用的伪选择器其实性能并不好,jQuery需要搜索每一个元素来定位,一定要斟酌使用
使用的话最好缩小范围 e.g.$(‘wrapper’).find/filter(‘:animated’)综上,
- 尽量使用ID、标签选择器(class选择器前叠加标签选择器)
- 尽量为选择器指定上下文
2.缓存jq对象
缓存思想对于提高性能的重要性那是不言而喻的
我在循环语句的性能问题容中也提到了这种思想
看看你的代码中有没有类似这样的写法
//待改进
$('#wrapper div.demo').css('background-color','red');
$('#wrapper div.demo').animate('top','100px');
$('#wrapper div.demo').on('click',function(){...});
......
这样做的结果是,每行都要创建一个一模一样的jQuery对象,并且每次都要去查找DOM
所以我们可以最好这样做
//待改进
$demo = $('#wrapper div.demo');
$demo.css('background-color','red');
$demo.animate('top','100px');
$demo.on('click',function(){...});
......
把对象都缓存到一个变量里,这样避免了它多次查找DOM,避免多次创建对象
而且看起来也清爽了许多不是么
变量前加“$”符号代表它是一个jQuery对象,用以区别普通变量
如果你想在其它函数中使用jQuery对象,那么我们可以缓存到全局,像这样
window.$my = {
head: $('#head'),
content: $('#content'),
footer: $('#footer'),
...
}
function foo(){
$my.head.css(...);
}
只要记住一点就好了
不要在你的代码里出现重复的选择器
3.链式调用
链式调用算是jQuery的特点了
仅仅是简单的在函数中返回了这个对象,便实现了像一条链子的调用方式
我特意在上面的代码中同样标注了“待改进”就是怕大家把它刻在心里……[]~( ̄▽ ̄)~*
我们来修改一下代码
$demo = $('#wrapper div.demo');
$demo.css('background-color','red')
.animate('top','100px')
.on('click',function(){...});
或者如果你以后都不会用到这个选择器,干脆
$('#wrapper div.demo').css('background-color','red')
.animate('top','100px')
.on('click',function(){...});
不缓存也可以
毫无疑问使用jQuery的链式调用可以有效提高性能
而且这样更简洁、更优雅……
4.循环DOM操作
虽然很多jQuery方法很方便,但是方便的同时会带来性能问题,一定要慎重使用
循环和DOM操作都是影响性能的关键
更不要在循环中获取jq对象
这里有个小问题要注意
var $list = $('ul.list');
for(var i = 0, i < 100; i++){
$list.append('<li>' + ... + '</li>');
}
这样直接在每次迭代中插入DOM节点,十分耗性能
我们可以这样做
var $list = $('ul.list');
var temp = '';
for(var i = 0; i < 100; i++){
temp += '<li>' + ... + '</li>';
}
$list.html(temp);
5.精简代码
简化代码确实可以提高性能
比如像这样的代码
$demo.css('width','100px');
.css('height','100px');
.css('color','red');
这样太麻烦了,可以改写(只是举个例子,倒是没人这样写)
$demo.css({
'width': '100px',
'height': '100px',
'color': 'red'
});
6.拼接字符串
使用join()来拼接字符串而不是用“+”
这个提升性能的小技巧不局限于jQuery
在原生js中我们也应该注意
var arr = [];
for(var i = 0; i < 100; i++){
arr[i] = '<div class="demo' + i + '">'
}
('.wrapper').html(arr.join());
join()能够优化性能
7.使用原生js
并不是说让大家都使用原生js
那这个jquery类库就没意义了
我的意思是说如果使用原生js同样可以很简单的解决问题,那么就使用原生js吧
这可以提高性能
然我想起了一句广告词“劲酒虽好,可我要贪杯哦”(感觉好奇怪)
jQuery虽然好,但使用要适度
比如$.each有时候换成for循环也许会更好
再比如$(this).css(‘color’,’red’) 换成 this.style.color = ‘red’
还有很多,如果兼容问题并不是很了解,还是建议使用jQuery提供的方法
毕竟在这方面jQuery处理的很棒
8.事件委托
JavaScript中的事件都会冒泡到父级
所以假如ul下面有1亿个li(虽然不可能)
那么就把事件绑定在ul上吧,然后判断触发事件的源对象
在jQuery中,我们使用on来实现
$('ul').on('click','li',function(){
......
});
性能肯定要比
$('li').on('click',function(){
.......
});
强很多
假如真有一亿个li,那你也只能使用事件委托/事件代理了
这个事件委托的优势不仅仅是这样
如果你在ul的下面新添加li,它同样会冒泡给父级,由父级代理处理
这样避免了修改或添加代码,增加绑定事件
9.直接函数
我们应该使用底层的直接函数
这个问题很好理解
比如我们应该使用
10.扩展插件
如果你的代码需要被多次调用,
建议大家把代码创建为插件
jQuery中扩展插件的方法有两种
$.extend() 封装全局函数的插件(还可以扩展自定义插件但不怎么用)
$.fn.extend() 封装对象方法的插件
这个扩展插件日后我会写一个专题
11.库更新
最后一点就很简单了
jQuery版本的更新便会优化性能、修复bug或者增加方法
同时也可能删除一些不常用的方法,毕竟不是完全向后兼容的
总结
- 尽量使用ID、标签选择器
- 尽量为选择器指定上下文/使用find()
- 避免出现重复选择器,缓存jq对象
- 链式调用
- 避免循环内获取jq对象
- 尽量避免循环中DOM操作
- 尽量减少对HTML结构的修改
- 注意精简代码
- 使用join()拼接字符串
- 需要的时候使用原生JavaScript
- 使用on()事件委托
- 扩展插件,提高重用性
- 注意更新库版本