对于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 相关文章推荐
Js 获取Gridview选中行的内容操作步骤
Feb 05 Javascript
jQuery实现左右切换焦点图
Apr 03 Javascript
JavaScript实现基于Cookie的存储类实例
Apr 10 Javascript
jquery实现超简洁的TAB选项卡效果代码
Aug 28 Javascript
JS实现鼠标滑过链接改变网页背景颜色的方法
Oct 20 Javascript
原生js实现图片轮播特效
Dec 18 Javascript
JavaScript入门系列之知识点总结
Mar 24 Javascript
jQuery实现html table行Tr的复制、删除、计算功能
Jul 10 jQuery
AngularJS中重新加载当前路由页面的方法
Mar 09 Javascript
vue v-for循环重复数据无法添加问题解决方法【加track-by='索引'】
Mar 15 Javascript
ES6中的class是如何实现的(附Babel编译的ES5代码详解)
May 17 Javascript
JavaScript数组 几个常用方法总结
Nov 11 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
资料注册后发信小技巧
2006/10/09 PHP
php下通过curl抓取yahoo boss 搜索结果的实现代码
2011/06/10 PHP
phpmyadmin安装时提示:Warning: require_once(./libraries/common.inc.php)错误解决办法
2011/08/18 PHP
PHP使用strtotime计算两个给定日期之间天数的方法
2015/03/18 PHP
PHP精确计算功能示例
2016/11/29 PHP
利用php操作memcache缓存的基础方法示例
2017/08/02 PHP
在网页中屏蔽快捷键
2006/09/06 Javascript
更换select下拉菜单背景样式的实现代码
2011/12/20 Javascript
Jquery easyUI 更新行示例
2014/03/06 Javascript
jQuery 获取/设置/删除DOM元素的属性以a元素为例
2014/05/23 Javascript
浅谈Javascript Base64 加密解密
2014/12/28 Javascript
JS模仿腾讯图片站的图片翻页按钮效果完整实例
2016/06/21 Javascript
深入理解jQuery3.0的domManip函数
2016/09/01 Javascript
JavaScript学习笔记整理_用于模式匹配的String方法
2016/09/19 Javascript
jQuery Validate验证框架详解(推荐)
2016/12/17 Javascript
深入理解angular2启动项目步骤
2017/07/15 Javascript
基于AngularJS拖拽插件ngDraggable.js实现拖拽排序功能
2019/04/02 Javascript
vue项目使用.env文件配置全局环境变量的方法
2019/10/24 Javascript
JavaScript设计模式之策略模式实现原理详解
2020/05/29 Javascript
对Python 网络设备巡检脚本的实例讲解
2018/04/22 Python
python程序变成软件的实操方法
2019/06/24 Python
python脚本当作Linux中的服务启动实现方法
2019/06/28 Python
python Manager 之dict KeyError问题的解决
2019/12/21 Python
Pytorch实现神经网络的分类方式
2020/01/08 Python
Python基于smtplib协议实现发送邮件
2020/06/03 Python
tensorflow 2.1.0 安装与实战教程(CASIA FACE v5)
2020/06/30 Python
从Pytorch模型pth文件中读取参数成numpy矩阵的操作
2021/03/04 Python
TripAdvisor印尼站:全球领先的旅游网站
2018/03/15 全球购物
献爱心标语
2014/06/21 职场文书
中国文明网向国旗敬礼寄语大全
2014/09/27 职场文书
机关作风整顿个人整改措施思想汇报
2014/09/29 职场文书
教师学习三严三实心得体会
2014/10/13 职场文书
导游词之嵊泗列岛
2019/10/30 职场文书
幼师必备:幼儿园期末教师评语50条
2019/11/01 职场文书
Nginx+Tomcat负载均衡集群的实现示例
2021/10/24 Servers
Redis实战高并发之扣减库存项目
2022/04/14 Redis