对于jQuery性能的一些优化建议


Posted in Javascript onAugust 13, 2015

不要每次都在循环中访问数组的 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%。

// 当元素少于 20 个时使用这个方法,多余 20 个时,速度就慢了
$('a.swedberg').css('color', '#asd123');

// 多余 20 个元素时,应考虑直接在页面中添加 style 标签
$('<style type="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);
  return this;
}

$('li.cartitems').doOnce(function(){
  // 这里可以确保结果集不是空的
});

这种方法特别适用于 jQuery UI 方面,因为即使结果集中不包含任何元素,其开销也会很大。
变量的定义

可以在一条语句中定义多个变量:

// 老掉牙的写法
var test = 1;
var test2 = function() { ... };
var test3 = test2(test);

// 新写法
var test = 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]) { ... }
Javascript 相关文章推荐
use jscript Create a SQL Server database
Jun 16 Javascript
我见过最全的个人js加解密功能页面
Dec 12 Javascript
window.location.reload()方法刷新页面弹出要再次显示该网页对话框
Apr 24 Javascript
JavaScript charCodeAt方法入门实例(用于取得指定位置字符的Unicode编码)
Oct 17 Javascript
JavaScript6 let 新语法优势介绍
Jul 15 Javascript
AngularJS实现ajax请求的方法
Nov 22 Javascript
全选复选框JavaScript编写小结(附代码)
Aug 16 Javascript
JavaScript中使用参数个数实现重载功能
Sep 01 Javascript
Angularjs过滤器实现动态搜索与排序功能示例
Dec 13 Javascript
Vue Router的懒加载路径的解决方法
Jun 21 Javascript
Vue开发之封装上传文件组件与用法示例
Apr 25 Javascript
js实现头像上传并且可预览提交
Dec 25 Javascript
使用控制台破解百小度一个月只准改一次名字
Aug 13 #Javascript
js实现文本框宽度自适应文本宽度的方法
Aug 13 #Javascript
理解和运用JavaScript的闭包机制
Aug 13 #Javascript
详解JavaScript中jQuery和Ajax以及JSONP的联合使用
Aug 13 #Javascript
JavaScript的面向对象编程基础
Aug 13 #Javascript
JavaScript简单判断复选框是否选中及取出值的方法
Aug 13 #Javascript
JavaScript实现将文本框的值插入指定位置的方法
Aug 13 #Javascript
You might like
php 小乘法表实现代码
2009/07/16 PHP
php whois查询API制作方法
2011/06/23 PHP
PHP中Cookie的使用详解(简单易懂)
2017/04/28 PHP
php利用云片网实现短信验证码功能的示例代码
2017/11/18 PHP
PHP实现类似题库抽题效果
2018/08/16 PHP
解决 FireFox 下[使用event很麻烦] 的问题.
2006/08/22 Javascript
jQuery下通过replace字符串替换实现大小图片切换
2012/05/22 Javascript
JavaSacript中charCodeAt()方法的使用详解
2015/06/05 Javascript
js验证身份证号有效性并提示对应信息
2015/10/19 Javascript
javascript如何写热点图
2015/12/08 Javascript
Javascript 实现放大镜效果实例详解
2016/12/03 Javascript
jquery实现提示语淡入效果
2017/05/05 jQuery
基于JavaScript实现微信抢红包功能
2017/07/20 Javascript
解决Vue使用mint-ui loadmore实现上拉加载与下拉刷新出现一个页面使用多个上拉加载后冲突问题
2017/11/07 Javascript
基于cropper.js封装vue实现在线图片裁剪组件功能
2018/03/01 Javascript
vue19 组建 Vue.extend component、组件模版、动态组件 的实例代码
2019/04/04 Javascript
12个提高JavaScript技能的概念(小结)
2019/05/09 Javascript
微信小程序上传图片并等比列压缩到指定大小的实例代码
2019/10/24 Javascript
浏览器JavaScript调试功能无法使用解决方案
2020/09/18 Javascript
在Python上基于Markov链生成伪随机文本的教程
2015/04/17 Python
Python实现根据IP地址和子网掩码算出网段的方法
2015/07/30 Python
python编程实现归并排序
2017/04/14 Python
解决pycharm界面不能显示中文的问题
2018/05/23 Python
修改Pandas的行或列的名字(重命名)
2019/12/18 Python
如何利用python进行时间序列分析
2020/08/04 Python
css3中用animation的steps属性制作帧动画
2019/04/25 HTML / CSS
巴西最大的体育用品商城:Netshoes巴西
2016/11/29 全球购物
给老师的一封建议书
2014/03/13 职场文书
厉行勤俭节约倡议书
2014/05/16 职场文书
2014年会计主管工作总结
2014/12/20 职场文书
离婚起诉书范文2015
2015/05/19 职场文书
严以用权学习心得体会
2016/01/12 职场文书
2016七夕情人节广告语
2016/01/28 职场文书
解析mybatis-plus中的resultMap简单使用
2021/11/23 Java/Android
SQL Server使用导出向导功能
2022/04/08 SQL Server
Go gorilla/sessions库安装使用
2022/08/14 Golang