你的位置:首页 > Java教程

[Java教程]基于jQuery查找dom的多种方式性能问题


这个问题的产生由于我们前端组每个人的编码习惯的差异,最主要的还是因为代码的维护性问题。在此基础上,我对jQuery源码(1.11.3)查找dom节点相关的内容进行了仔细的查阅,虽然并不能理解的很深入 。。同时基于对浏览器console对象的了解产生了一系列之后的问题和分析,对jQuery最常用的三种dom查找方式进行了一个查找效率和性能方面的比较分析。

首先我们要用到的是   console.time()   和   console.timeEnd()   这两个成对出现的console对象的方法,该方法的用法是将他们两者之间的代码段执行并输出所消耗的执行时间,并且两者内传入的字符串命名须统一才能生效,例如:

1 console.time('Scott');2 console.log('seven');3 console.timeEnd('Scott');4 seven5 Scott: 0.256ms

代码段中三处一致才是正确的用法。

接下来我们来讨论我们常用的jQuery查找dom方式:

  1. $('.parent .child');

  2. $('.parent').find('.child');

  3. $('.child','.parent');

其中方式1和方式3都是基于jQuery的selector和context的查找方式,既我们最常用的jQuery()或者$(),

详细即为:

1 jQuery = function( selector, context ) {2   // The jQuery object is actually just the init constructor 'enhanced'3   // Need init if jQuery is called (just allow error to be thrown if not included)4   return new jQuery.fn.init( selector, context );5 }

基于jQuery(1.11.3)70行处,为该方法的入口,他做的所有事情就是创建了一个jquery.fn上的init方法的对象,我们再来细看这个对象是什么:

 1   init = jQuery.fn.init = function( selector, context ) { 2     var match, elem; 3  4     // HANDLE: $(""), $(null), $(undefined), $(false) 5     if ( !selector ) { 6       return this; 7     } 8  9     // Handle HTML strings 10     if ( typeof selector === "string" ) { 11       if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { 12         // Assume that strings that start and end with <> are HTML and skip the regex check 13         match = [ null, selector, null ]; 14  15       } else { 16         match = rquickExpr.exec( selector ); 17       } 18  19       // Match html or make sure no context is specified for #id 20       if ( match && (match[1] || !context) ) { 21  22         // HANDLE: $(html) -> $(array) 23         if ( match[1] ) { 24           context = context instanceof jQuery ? context[0] : context; 25  26           // scripts is true for back-compat 27           // Intentionally let the error be thrown if parseHTML is not present 28           jQuery.merge( this, jQuery.parseHTML( 29             match[1], 30             context && context.nodeType ? context.ownerDocument || context : document, 31             true 32           ) ); 33  34           // HANDLE: $(html, props) 35           if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { 36             for ( match in context ) { 37               // Properties of context are called as methods if possible 38               if ( jQuery.isFunction( this[ match ] ) ) { 39                 this[ match ]( context[ match ] ); 40  41               // ...and otherwise set as attributes 42               } else { 43                 this.attr( match, context[ match ] ); 44               } 45             } 46           } 47  48           return this; 49  50         // HANDLE: $(#id) 51         } else { 52           elem = document.getElementById( match[2] ); 53  54           // Check parentNode to catch when Blackberry 4.6 returns 55           // nodes that are no longer in the document #6963 56           if ( elem && elem.parentNode ) { 57             // Handle the case where IE and Opera return items 58             // by name instead of ID 59             if ( elem.id !== match[2] ) { 60               return rootjQuery.find( selector ); 61             } 62  63             // Otherwise, we inject the element directly into the jQuery object 64             this.length = 1; 65             this[0] = elem; 66           } 67  68           this.context = document; 69           this.selector = selector; 70           return this; 71         } 72  73       // HANDLE: $(expr, $(...)) 74       } else if ( !context || context.jquery ) { 75         return ( context || rootjQuery ).find( selector ); 76  77       // HANDLE: $(expr, context) 78       // (which is just equivalent to: $(context).find(expr) 79       } else { 80         return this.constructor( context ).find( selector ); 81       } 82  83     // HANDLE: $(DOMElement) 84     } else if ( selector.nodeType ) { 85       this.context = this[0] = selector; 86       this.length = 1; 87       return this; 88  89     // HANDLE: $(function) 90     // Shortcut for document ready 91     } else if ( jQuery.isFunction( selector ) ) { 92       return typeof rootjQuery.ready !== "undefined" ? 93         rootjQuery.ready( selector ) : 94         // Execute immediately if ready is not present 95         selector( jQuery ); 96     } 97  98     if ( selector.selector !== undefined ) { 99       this.selector = selector.selector;100       this.context = selector.context;101     }102 103     return jQuery.makeArray( selector, this );104   }

基于jQuery(1.11.3) 2776行处,该方法比较长,我就来大概说一下我对这个方法的了解:这里主要就是做了先对selector的判断,在判断完后,查找context如果存在就继续做对有context存在情况的处理,没有则进行没有context情况的处理,而方式1和方式3:

  1. $('.parent .child');

  3. $('.child','.parent');

他们都要进入相同的判断步骤,即上面简要说明的判断流程,等到1和3判断完后所花费的时间基本差不多,但是1内部的选择器还需要花费时间去查找,得出

  方式1. $('.parent .child');  走完流程花费的时间:a;

  方式3. $('.child','.parent');  走完流程花费的时间:a; 几乎已经找到dom节点

      方式1. $('.parent .child');  查找选择器.parent .child花费的时间:b;

      所以得出初步结论:方式3. $('.child','.parent');花费的时间:a;    方式1. $('.parent .child');花费的时间:a + b;  方式3优于方式1

      接下来我们来看实际的运行结果:

      

以百度页面为例,我们随便找出一组满足的范围来查找,博主进行多次测试,方式3的查找效率均快于方式1,且方式3的查找速度基本为方式1的3倍左右,即:

接下来我们我们加入jQuery的find方法进行比较,即为:

  方式1. $('.parent .child');

  方式2. $('.parent').find('.child');

  方式3. $('.child','.parent');

由于我们已有了之前的判断,基于他们三者都要进行jQuery()的查找,所以三者都在此花费a的查找时间,此时方式3已经基本找到了:

  方式3. $('.child','.parent'); 花费时间:a;

     接下来方式1进行 '.parent .child'选择器的查找,方式2进行jQuery的find方法查找,在此列出find的具体内容:

 1 find: function( selector ) { 2     var i, 3       ret = [], 4       self = this, 5       len = self.length; 6  7     if ( typeof selector !== "string" ) { 8       return this.pushStack( jQuery( selector ).filter(function() { 9         for ( i = 0; i < len; i++ ) {10           if ( jQuery.contains( self[ i ], this ) ) {11             return true;12           }13         }14       }) );15     }16 17     for ( i = 0; i < len; i++ ) {18       jQuery.find( selector, self[ i ], ret );19     }20 21     // Needed because $( selector, context ) becomes $( context ).find( selector )22     ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );23     ret.selector = this.selector ? this.selector + " " + selector : selector;24     return ret;25   }

基于jQuery(1.11.3) 2716行处,在此我们可以看出find的过程比较简单,相较于方式1查找复杂的选择器(在查找选择器的过程中需要排除很多的情况,更多的时间花费在处理字符串上,即处理出我们想要表达的选择器)更高效一点,我们得出方式2优于方式1,下面我们拿三者来进行比较:

我们可以看出,方式1最慢,方式2和方式3不相上下,方式3略胜一筹,基本吻合我们的初衷,即为:

在基于jQuery查找dom的过程中能使用jquery的查找方式就使用,尽量不写复杂的选择器来表达我们想要查找的dom,效率极低。相反使用jquery的查找方式我们就能尽量排除复杂选择器的情况,极大提高查找效率。

由于方式2的使用可能会受限,所以在此我推荐大家使用方式3,即为:

  

写到这里,突然感觉好像对自己并没有什么(luan)用,写的好像我的编码能力已经强到了来拼dom查找效率的地步 。。。

原创,转载请注明。by Scott.




深圳到英国旅游深圳去英国旅游报价深圳到爱尔兰旅游深圳去爱尔兰旅游报价深圳到比利时旅游深圳图书馆开放时间是什么时候? 泰国购物怎么刷卡合算? 看霾前霾后的津城美景对比照 走进天然的油画世界 新疆五彩滩 中山长涨浪漫水城电话?中山浪漫水城门票学生证半价吗? 长江水世界会员卡多少钱一张?中山长江水世界会员卡怎么办? 2015长江水世界中秋节活动?中山长江水世界中秋节门票多少钱? 深圳观澜水上乐园报价多少?观澜水上乐园优惠票怎么买? 2015五月份广州百万葵园都有什么花呢? 请问惠州巽寮湾好玩,还是阳西沙扒湾? 惠州有什么民风民俗呢? 惠州南昆山有什么好玩的地方?南昆山怎么样 2015深圳圣诞节平安夜哪里有活动?深圳圣诞夜场去哪好玩? 2015广州长隆圣诞节夜场活动时间?番禺长隆欢乐世界圣诞夜场几时开始? 2015-2015浙江卫视广州跨年演唱会节目单?奔跑吧兄弟跨年演唱会门票预定? 2015-2015浙江卫视跨年演唱会明星有谁?奔跑吧兄弟跨年演唱会在哪里举办? LP3891EMRX-1.5/NOPB Datasheet LP3891EMRX-1.5/NOPB Datasheet LM3673TLX-1.8/NOPB Datasheet LM3673TLX-1.8/NOPB Datasheet LP3891EMRX-1.8 Datasheet LP3891EMRX-1.8 Datasheet 岘港天气 岘港天气 岘港天气 香港南丫岛旅游攻略 香港南丫岛旅游攻略 香港南丫岛旅游攻略 自驾游注意事项 自驾游注意事项 自驾游注意事项