jQuery 性能优化
关于选择器
-
总是从 ID 选择器开始继承
jQuery 选择器对 ID 的选择是使用原生的 getElementById() 方法,因此从最近的 id 选择器开始继承,可以避免不必要的 DOM 遍历和循环 (单个元素直接选择,多个元素遍历数目可以减少很多) -
在 class 前使用 tag (标签名)
jQuery 对元素选择使用的也是原生的 getElementsByTagName() 方法使用 tag 标签修饰 class 时的注意点- 不要使用 tag 修饰 id, id永远是最快的
$(input #username)
- 不要画蛇添足的使用 id 来修饰 id
$(#footer #footernav)
- 如果使用属性选择器,尽量使用 tag 来修饰
$(input[row='c3221'])
- 不要使用 tag 修饰 id, id永远是最快的
-
尽量使用 ID 代替 class
ID 选择器调用原生getElementById()
方法是所有选择中速度最快的。
具体使用还是要更具实际情况,组织好代码以及命名规范。 -
给选择器一个上下文
jQuery 选择器中有一个这样的选择器,它能指定上下文。jQuery(expression, context)
通过使用它可以缩小选择器在 DOM 中搜索的范围,达到节省事件,提高效率
$('.myDiv') -- 推荐写法 -- $('.myDiv', $('#context'))
个人感觉这一点与
$('#context .myDiv')
类似 -
正确使用子选择器与后代选择器
与 CSS 的子选择器和后代选择器类似使用的时候避免只是用子选择器,却使用了后代选择器的情况$('parentSelector childrenSelector') // parentSelector 节点下任意层级(后代)的 childrenSelector 匹配值 $('parentSelector > childrenSelector') // parentSelector 节点子元素中满足 childrenSelector 匹配值
-
缓存 jQuery 对象与链式调用
永远不要让相同的选择器在代码里出现多次,每次都以为这一个新的遍历查询
jQuery 的链式调用机制可以减少同一选择器的多次出现可选的 tips:
-
为了区分普通的 JavaScript 对象和 jQuery 对象,可以在 jQuery 对象名前加上 $ 符号。
-
可以使用 jQuery 的链式调用改善选择器多次选择的性能问题。
$('some-selector').on('click',function(){}) .on('mouseover', function(){}) .on('mouseout', function(){}) -- 避免这样的写法 -- $('some-selector').on('click',function(){}) $('some-selector').on('mouseover', function(){}) $('some-selector').on('mouseout', function(){})
-
可以按照自己的需求将 jQuery 对象存储在一个对象里面,从对象里面直接取 jQuery 对象,同时生成了一个 $ 构成的命名空间的感觉
window.$my = { header: $('head'), content: $('div .content'), footer: $('footer') }
-
关于 DOM 操作
-
使用 DocumentFrame 的思想
直接操作 DOM 的成本,不管是使用原生 JavaScript 还是 jQuery 的开销都很大,所以每次进行 DOM 操作都尽可能的一次更新多个元素,在原生 JavaScript 中表现为使用 DocumentFrame 的方式进行 DOM 更新,在 jQuery 中推荐先将需要添加的 DOM 结构用 String 拼接好,一次 DOM 操作更新多个 DOM
var top_100_li = [...], $mylist = $('#mylist'), top_100_listring = ''; // 先使用 top_100_listring 将要添加的 list string 保存起来 for(var i = 0, len = top_100_li.length; i < len ; i++) { top_100_listring += '<li>' + tp_100_li[i] + '</li>'; } // 一次 DOM 操作更新 100 个 list $mylist.html(top_100_listing); -- 每次都操作DOM的低效使用形式 -- var top_100_li = [...], $mylist = $('#mylist'), top_100_listring = ''; for(var i = 0, len = top_100_li.length; i < len ; i++) { // 每次都执行 DOM 更新操作 $mylist.append('<li>' + tp_100_li[i] + '</li>'); }
关于事件绑定问题
-
尽可能的使用冒泡与捕获的方式,避免不必要的事件绑定
除非在特殊情况下,否则每个 js 事件都会冒泡到父级节点,当一个父级节点的后代都具有同样的事件绑定时,将事件绑定在父级节点上能代理效率很低的为每个子元素都添加事件监听。
主要使用到的技术是 event 对象包含
target || srcElement
属性,表明具体由哪一个元素触发了事件。$('table .myTable').off().on('click', function(e) { var ev = e || window.event, target = ev.target || ev.srcElement, $target = $(target); //如果只是对特定元素执行事件 if($target ... 不是特定元素 ){ return } // $target.doSomething }) -- 不推荐的写法 -- $('table .myTable td').off().on('click', function(e) { // doSometing ... })
-
慎用
.live()
方法
这个方法个人学习工作中使用较少,仅供读者参考。
jQuery 1.3.1 版本之后增加的方法,功能是为新增的 DOM 元素动态绑定事件。但对于效率来说,这个方法比较占用资源。所以建议不使用。$('p').live('click', function() { // doSomething ... }) $('body').append('<p>新增的 p 元素</p>') // 此时的 p 元素以及绑定了对应的事件 -- 推荐写法 -- $('body').append( $('<p>新增的 p 元素</p>') .on('click', function() { // doSomething ... }) )
其他方法
-
压缩 JavaScript
压缩 JavaScript 代码可以使加载代码的时间更短,更快的开始执行对应的函数和方法。能减少用户等待的时间提升用户体验。
-
使用
data()
方法存储临时变量// 不使用data()方法 $(function() { var flag = false; $('button').on('click', function() { if(flag) { $('p').text('true'); flag = false; } else { $('p').text('false'); flag = true; } }) }) // 使用data()方法 $(function() { $('button').on('click', function() { if($('p').data('flag')) { $('p').text('true'); $('p').data('flag', false) } else { $('p').text('false'); $('p').data('flag', true) } }) })
不知道什么时候网盘里面多了个几篇 jQuery性能优化指南,今天看了一下,顺便将文章重新组织了一下,拿出来和大家分享,如有侵权请联系<a href="mailto:swuyxr@163.com">swuyxr@163.com</a>删除。