对于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 相关文章推荐
用dom+xhtml+css制作的一个相册效果代码打包下载
Jan 24 Javascript
遨游,飞飞,IE,空中网 浏览器无提示关闭方法
Jul 11 Javascript
jQuery实现类似滑动门切换效果的层切换
Sep 23 Javascript
关于删除时的提示处理(确定删除吗)
Nov 03 Javascript
javascript中parentNode,childNodes,children的应用详解
Dec 17 Javascript
javascript最基本的函数汇总
Jun 25 Javascript
详解自动生成博客目录案例
Dec 09 Javascript
jQuery中clone()函数实现表单中增加和减少输入项
May 13 jQuery
微信小程序 setData 对 data数据影响问题
Apr 18 Javascript
JS学习笔记之原型链和利用原型实现继承详解
May 29 Javascript
Node.js实现简单的爬取的示例代码
Jun 25 Javascript
浅谈Vue2.4.0 $attrs与inheritAttrs的具体使用
Mar 08 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/08/05 PHP
JS 实现导航栏悬停效果(续2)
2013/09/24 Javascript
详谈javascript中DOM的基本属性
2015/02/26 Javascript
在jQuery中处理XML数据的大致方法
2015/08/14 Javascript
JS实现的表格操作类详解(添加,删除,排序,上移,下移)
2015/12/22 Javascript
windows下vue-cli及webpack搭建安装环境
2017/04/25 Javascript
javascript 取小数点后几位几种方法总结
2017/08/02 Javascript
基于Vue的移动端图片裁剪组件功能
2017/11/28 Javascript
基于substring()和substr()的使用以及区别(实例讲解)
2017/12/28 Javascript
详解Vue CLI3配置之filenameHashing使用和源码设计使用和源码设计
2018/08/31 Javascript
浅谈webpack4.x 入门(一篇足矣)
2018/09/05 Javascript
vue.js的vue-cli脚手架中使用百度地图API的实例
2019/01/21 Javascript
javascript随机变色实例代码
2019/10/15 Javascript
浅谈vue中$event理解和框架中在包含默认值外传参
2020/08/07 Javascript
vue实现桌面向网页拖动文件的示例代码(可显示图片/音频/视频)
2021/03/01 Vue.js
[03:42]2018完美盛典-《加冕》
2018/12/16 DOTA
Python 的 with 语句详解
2014/06/13 Python
Python基于scapy实现修改IP发送请求的方法示例
2017/07/08 Python
Python实现类似比特币的加密货币区块链的创建与交易实例
2018/03/20 Python
深入浅析Python2.x和3.x版本的主要区别
2018/11/30 Python
Python将string转换到float的实例方法
2019/07/29 Python
pandas dataframe 中的explode函数用法详解
2020/05/18 Python
Python实现爬取网页中动态加载的数据
2020/08/17 Python
提高python代码运行效率的一些建议
2020/09/29 Python
Docker如何部署Python项目的实现详解
2020/10/26 Python
pytest fixtures装饰器的使用和如何控制用例的执行顺序
2021/01/28 Python
韩国现代百货官网:Hmall
2018/03/21 全球购物
受希腊女神灵感的晚礼服、鸡尾酒礼服和婚纱:THEIA
2018/04/15 全球购物
L’AGENCE官网:加州女装品牌
2018/06/03 全球购物
加拿大品牌鞋包连锁店:Little Burgundy
2021/02/28 全球购物
总经理文秘岗位职责
2014/02/03 职场文书
《凡卡》教学反思
2014/04/09 职场文书
优秀家长事迹材料
2014/05/17 职场文书
市级绿色学校申报材料
2014/08/25 职场文书
肖申克的救赎观后感
2015/06/02 职场文书
推普标语口号大全
2015/12/26 职场文书