jQuery性能优化

前言,最近在写jquery的时候,出现一下性能相关问题,在此特作总结,以待日后多加注意。

1.关于变量的定义

这里不仅仅是jquery,即便是javascript都是一样的,一定要使用var(let/const)关键字来定义变量,不能定义成如下:

$abc = $('#abc'); //这是个全局的定义,一旦在别处出现相同名字的引用就会报错,还不一定能找到错误来源

如果有多个变量需要定义的时候,可以如下做:

var item = 0,
   $ifr = $('#ifr'),
   $pop-class = $('.pop-class');

在定义jquery变量时添加$符号到变量前面,这样做的好处就是,你可以很有效的提示自己这是一个jquery的变量。如下:

var $jump-client = $('#jump-client');

2.关于DOM操作

当使用jquery库时,尤其是在页面中需要大量的访问和操作DOM元素的时候,将其缓存起来会获得更好的性能。
因为我们在每次通过选择器构建一个新的jquery对象的时候,jQuery的核心部分的Sizzle引擎会遍历DOM然后通过对应的选择器来匹配真正的dom元素。这种方式比较低效,在现代浏览器中可以通过document.querySelector方法通过传入对应的Class参数来匹配对应的元素,不过IE8以下版本不支持此方法。
一个提高性能的实践是通过变量缓存jQuery对象。如下:

//html:
<ul id="pancakes" >
    <li>first</li>
    <li>second</li>
    <li>third</li>
    <li>fourth</li>
    <li>fifth</li>
</ul>

不好的处理方式:

 $('#pancakes li').eq(0).remove();
 $('#pancakes li').eq(1).remove();
 $('#pancakes li').eq(2).remove();

jquery缓存方式:

var pancakes = $('#pancakes li');
pancakes.eq(0).remove();
pancakes.eq(1).remove();
pancakes.eq(2).remove();
// ------------------------------------
// 或者:
// pancakes.eq(0).remove().end()
//  .eq(1).remove().end()
//  .eq(2).remove().end();

将pancakes li提前存储在pancakes中,再之后进行操作的时候可直接调用pancakes即可,这样就避免了大量的$符号,使得DOM树不再被重复遍历来寻找被操作的元素。

3.代码精简

在操作元素的css属性的时候,尽量使得代码看起来足够的精简,避免大量的重复操作:
不好的写法如下:

$button.click(function(){
    $target.css('width','50%');
    $target.css('border','1px solid #202020');
    $target.css('color','#fff');
});

该如此做,会好很多:

$button.click(function(){
    $target.css({'width':'50%','border':'1px solid #202020','color':'#fff'});
});

其次,避免在一个$中重复叠加多个id:

$('#something #children');  => $('#children');

最后可使用逻辑判断来提速:

if(!$something) {
    $something = $('#something ');
} 
||
$something= $something|| $('#something'); //这样相对更好

4.关于图片的优化

  • 图片的预加载:如果网页中使用很多的图片文件,当鼠标悬停而展示的图片文件的时候,预加载是很有意义:
$.preloadImages = function () {
  for (var i = 0; i < arguments.length; i++) {
    $('<img>').attr('src', arguments[i]);
  }
};
 
$.preloadImages('img/hover-on.png', 'img/hoveroff.png');
  • 其次,判定图片是否加载完成:有的时候可能需要检查图片是否加载完成然后来进行相应的逻辑处理,其判定如下:
$('img').load(function () {
  console.log('image load successful');
});
  • 自动修补破损的图像:如果网站上出现了许多破损的图片,一个个的去更换是很麻烦的,所以可以使其自动的修补断开的图像链接:
$('img').on('error', function () {
  if(!$(this).hasClass('broken-image')) {
    $(this).prop('src', 'img/broken.png').addClass('broken-image');
  }
}); 

5.使用data()函数来存储状态

使用jquery的data()存储和检索与特定的DOM元素相关的数据,它支持各种数据类型,包括javascript对象,同时它也支持HTML视图与数据的真正分离,通过保持数据隐藏同时也与特定的DOM元素关联。

例如:

//这里是html结构
<table>
    <tbody>
        <tr>
            <td>Shady Grove</td>
            <td>Aeolian</td>
        </tr>
        <tr>
            <td>Over the River, Charlie</td>
            <td>Dorian</td> 
        </tr>
    </tbody>
</table>

它会生成DOM图示如下:

在这里插入图片描述

有了 DOM,在 HTML 或 XML 文档(元素和内容)中创建的任何内容都可被程序化地访问、添加、删除或修改。

jQuery.cache 和 jQuery.data() 方法的定义如下:

(function( jQuery ) {
	jQuery.extend({
	cache: {},   
	uuid: 0,  
	expando: "jQuery" + jQuery.now(),
	 
	data: function( elem, name, data ) {
	    if ( !jQuery.acceptData( elem ) ) {
	        return;
	    }
	 
	    elem = elem == window ?
	        windowData :
	        elem;
 
	    var isNode = elem.nodeType,
	        id = isNode ? elem[ jQuery.expando ] : null,
	        cache = jQuery.cache, thisCache;
 
	    if ( isNode && !id && typeof name === "string" 
	&& data === undefined ) {
	        return;
	    }
    // 直接从对象获取数据
    if ( !isNode ) {
        cache = elem;
 
    // 计算元素的唯一ID
    } else if ( !id ) {
        elem[ jQuery.expando ] = id = ++jQuery.uuid;
    }

    // 除非不存在,否则避免生成新缓存
    if ( typeof name === "object" ) {
        if ( isNode ) {
            cache[ id ] = jQuery.extend(cache[ id ], name);
        } else {
            jQuery.extend( cache, name );
        }
    } else if ( isNode && !cache[ id ] ) {
        cache[ id ] = {};
    }
    thisCache = isNode ? cache[ id ] : cache;
 
    // 防止使用未定义的值覆盖命名高速缓存
    if ( data !== undefined ) {
        thisCache[ name ] = data;
    }
    return typeof name === "string" ? thisCache[ name ] : thisCache;
},
······

6.定义可复用的函数

如果定义一个内联(inline)回调函数同时这个包含多个元素的jQuery对象(正如上面所说的第一个例子),对于这个集合中的每个元素都会在内存中保存一个回调函数的副本。

例如:

//html
<button id="menuButton" >Show Menu!</button>
<a href="#" id="menuLink" >Show Menu!</a>

js代码:

//不好的写法:
//这个会导致多个回调函数的副本占用内存
$('#menuButton, #menuLink' ). click(function(){
});

//好点的写法:
function showMenu(){
	alert('Showing menu!' );
······
}
$('#menuButton' ). click(showMenu);
$('#menuLink' ). click(showMenu);

7.使用数组的方式来遍历jquery对象的集合

jQuery each方法这种优雅实现是有代价的,有一个办法能够更快地遍历一个jQuery对象 => 就是通过数组来实现,jQuery对象集合就是一个类数组,具有length和value属性。
例如:

<ul id="testList" >
   <li>Item</li>
   <li>Item</li>
   <li>Item</li>
   <li>Item</li> 
   <li>Item</li>
   <li>Item</li>
   <li>Item</li>
   <li>Item</li>
   <li>Item</li>
   <!-- add 50 more -->
</ul>

js代码:

var arr = $('li'),
    iterations = 100000;
------------------------------
// Array实现:    
console.time('Native Loop');
for (var z = 0; z < iterations; z++) {
    var length = arr.length;
    for (var i = 0; i < length; i++) {
        arr[i];
    }
}
console.timeEnd('Native Loop');

------------------------------
// each实现:    
console.time('jQuery Each');
for (z = 0; z < iterations; z++) {
    arr.each(function(i, val) {
        this;
    });
}
console.timeEnd('jQuery Each');

8.其他优化

  • 检查对象:尽管jQuery不会抛出大量的异常给用户,但是也不要依赖于此。jQuery通常会执行了一大堆没用的函数之后才确定一个对象是否存在。所以在对一个作一系列引用之前,应先检查一下这个对象存不存在。

  • 使用直接函数,而不要使用与与之等同的函数:为了获得更好的性能,你应该使用直接函数如 . a j a x ( ) , 而 不 要 使 用 .ajax(),而不要使用 .ajax()使.get(), . g e t J S O N ( ) , .getJSON(), .getJSON(),.post(),因为后面的几个将会调用$.ajax()。

  • 使用Event Delegation:当一个容器中有许多节点,你想对所有的节点都绑定一个事件,delegation很适合这样的应用场景。

使用Delegation,我们仅需要在父级绑定事件,然后查看哪个子节点(目标节点)触发了事件。

你有一个很多数据的table的时候,你想对td节点设置事件,这就变得很方便。先获得table,然后为所有的td节点设置delegation事件:

$("table").delegate("td", "hover", function(){
$(this).toggleClass("hover");
});
  • 避免载入多余的代码:将Javascript代码放在不同的文件中是个好的方法,仅在需要的时候载入它们。这样你不会载入不必要的代码和选择器。也便于管理代码。

  • 压缩成一个主JS文件,将下载次数保持到最少:当已经确定了哪些文件是应该被载入的,那么将它们打包成一个文件。用一些开源的工具可以自动帮你完成,如使用Minify(和你的后端代码集成)或者使用JSCompressor,YUI Compressor 或 Dean Edwards JS packer等在线工具可以为你压缩文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值