WEB开发网
开发学院网页设计JavaScript jQuery:一次失败的优化尝试 阅读

jQuery:一次失败的优化尝试

 2011-05-17 19:50:28 来源:本站整理   
核心提示: 我经常抱怨jQuery的DOM操作性能并不优秀,并且经常尝试用一些方法去进行优化,jQuery:一次失败的优化尝试,但是越是优化,越是沮丧地发现jQuery其实已经做得很好,3.当提交事务时,对被选择的元素进行一次遍历,从使用者的角度能够进行的优化实在有限(这并不意味着jQuery的性能是优秀的, 反之只能说它是

  我经常抱怨jQuery的DOM操作性能并不优秀,并且经常尝试用一些方法去进行优化,但是越是优化,越是沮丧地发现jQuery其实已经做得很好,从使用者的角度能够进行的优化实在有限(这并不意味着jQuery的性能是优秀的, 反之只能说它是一个相对封闭的库,无法从外部介入进行优化)。这篇文章就记录一次失败的优化经历。

  优化思想

  这一次优化的思想来自于数据库。在数据库优化的时候,我们常会说“将大量的操作放在一个事务中一起提交,能有效提高效率”。虽然对数据库不了解的我并不知道其原因,但是“事务”的思想却为我指明了方向(虽然是错的……)。

  因此我尝试将“事务”这一概念引入到jQuery中,通过“打开”和“提交”事务,从外部对jQuery进行一些优化,其最重要的在于减少each函数的循环次数。

  众所周知,jQuery的DOM操作,以get all, set first为标准,其中用于设置DOM属性/样式的操作,几乎都是对选择出来的元素的一次遍历,jQuery.access函数就是其中最核心的部分,其中用于循环的代码如下:

php100.com/cms/uploads/allimg/110220/10033051Q-0.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>// Setting one attribute
php100.com/cms/uploads/allimg/110220/1003303K6-1.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
if ( value !== undefined ) {
php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  
// Optionally, function values get executed if exec is true
php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
  exec = !pass && exec && jQuery.isFunction(value);
php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
php100.com/cms/uploads/allimg/110220/1003306209-5.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  
for ( var i = 0; i < length; i++ ) {
php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    fn(
php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      elems[i],
php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      key,
php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      exec 
? value.call(elems[i], i, fn(elems[i], key)) : value,
php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      pass
php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    );
php100.com/cms/uploads/allimg/110220/1003304546-12.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  }

php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
php100.com/cms/uploads/allimg/110220/10033042R-2.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  
return elems;
php100.com/cms/uploads/allimg/110220/1003302Y1-15.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>}

  比如jQuery.fn.css函数就是这样的:

jQuery.fn.css = function( name, value ) {
  
// Setting 'undefined' is a no-op
  if ( arguments.length === 2 && value === undefined ) {
    
return this;
  }

  
return jQuery.access( this, name, value, true, function( elem, name, value ) {
    
return value !== undefined ?
      jQuery.style( elem, name, value ) :
      jQuery.css( elem, name );
  });
};

  因此,下面这样的代码,假设被选择的div元素有5000个,则要循环访问10000个节点:

  而在我的想法中,在一个“事务”中,可以如数据库的操作一般,通过保存所有的操作,在“提交事务”的时候统一进行,将10000次节点访问,减少至5000次,相当于提升了“1倍”的性能。

简单实现

  “事务”式的jQuery操作中,提供2个函数:

  1.begin:打开一个“事务”,返回一个事务的对象。该对象拥有jQuery的所有函数,但是调用函数并不会立刻生效,只有在“提交事务”后才会生效。

  2.commit:提交一个“事务”,保证所有事先调用过的函数都生效,交返回原本的jQuery对象。

  实现起来也很方便:

  1.创建一个“事务对象”,复制jQuery.fn上所有函数到该对象中。

  2.当调用某个函数时,在预先准备好的“队列”中添加调用的函数名和相关参数。

  3.当提交事务时,对被选择的元素进行一次遍历,对遍历中的每个节点应用“队列”中的所有函数。

  简单地代码如下:

php100.com/cms/uploads/allimg/110220/10033045T-16.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>var slice = Array.prototype.slice;
php100.com/cms/uploads/allimg/110220/100330Ca-17.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>jQuery.fn.begin 
= function() {
php100.com/cms/uploads/allimg/110220/1003305Q5-18.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  var proxy 
= {
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      _core: c,
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      _queue: []
php100.com/cms/uploads/allimg/110220/10033051U-21.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    }
,
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    key,
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    func;
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  
//复制jQuery.fn上的函数
php100.com/cms/uploads/allimg/110220/1003305Q5-18.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
  for (key in jQuery.fn) {
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    func 
= jQuery.fn[key];
php100.com/cms/uploads/allimg/110220/1003305Q5-18.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    
if (typeof func == 'function'{
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      
//这里会因为for循环产生key始终是最后一个循环值的问题
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      
//因此必须使用一个闭包保证key的有效性(LIFT效应)
php100.com/cms/uploads/allimg/110220/1003305Q5-18.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
      (function(key) {
php100.com/cms/uploads/allimg/110220/1003305Q5-18.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>        proxy[key] 
= function() {
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>          
//将函数调用放到队列中
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
          this._queue.push([key, slice.call(arguments, 0)]);
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>          
return this;
php100.com/cms/uploads/allimg/110220/10033051U-21.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>        }
;
php100.com/cms/uploads/allimg/110220/10033051U-21.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      }
)(key);
php100.com/cms/uploads/allimg/110220/10033051U-21.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    }

php100.com/cms/uploads/allimg/110220/10033051U-21.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  }

php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  
//避免commit函数也被拦截
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
  proxy.commit = jQuery.fn.commit;
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  
return proxy;
php100.com/cms/uploads/allimg/110220/10033023R-42.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>}
;
php100.com/cms/uploads/allimg/110220/10033045T-16.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
php100.com/cms/uploads/allimg/110220/100330Ca-17.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>jQuery.fn.commit 
= function() {
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  var core 
= this._core,
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    queue 
= this._queue;
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  
//仅一个each循环
php100.com/cms/uploads/allimg/110220/1003305Q5-18.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
  core.each(function() {
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    var i 
= 0,
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      item,
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      jq 
= jQuery(this);
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    
//调用所有函数
php100.com/cms/uploads/allimg/110220/1003305Q5-18.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
    for (; item = queue[i]; i++{
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>      jq[item[
0]].apply(jq, item[1]);
php100.com/cms/uploads/allimg/110220/10033051U-21.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>    }

php100.com/cms/uploads/allimg/110220/10033051U-21.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  }
);
php100.com/cms/uploads/allimg/110220/1003304D8-19.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  
return this.c;
php100.com/cms/uploads/allimg/110220/10033023R-42.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>}
;


1 2  下一页

Tags:jQuery 一次 失败

编辑录入:coldstar [复制链接] [打 印]
赞助商链接