jQuery查找dom的几种方法效率详解


Posted in jQuery onMay 17, 2017

前言

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

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

console.time('Scott');
console.log('seven');
console.timeEnd('Scott');
seven
Scott: 0.256ms

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

正文

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

1.$(‘.parent .child');
2.$(‘.parent').find(‘.child');
3.$(‘.child','.parent');

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

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

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

init = jQuery.fn.init = function( selector, context ) {
 var match, elem;

 // HANDLE: $(""), $(null), $(undefined), $(false)
 if ( !selector ) {
 return this;
 }

 // Handle HTML strings
 if ( typeof selector === "string" ) {
 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
 // Assume that strings that start and end with <> are HTML and skip the regex check
 match = [ null, selector, null ];

 } else {
 match = rquickExpr.exec( selector );
 }

 // Match html or make sure no context is specified for #id
 if ( match && (match[1] || !context) ) {

 // HANDLE: $(html) -> $(array)
 if ( match[1] ) {
 context = context instanceof jQuery ? context[0] : context;

 // scripts is true for back-compat
 // Intentionally let the error be thrown if parseHTML is not present
 jQuery.merge( this, jQuery.parseHTML(
 match[1],
 context && context.nodeType ? context.ownerDocument || context : document,
 true
 ) );

 // HANDLE: $(html, props)
 if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
 for ( match in context ) {
 // Properties of context are called as methods if possible
 if ( jQuery.isFunction( this[ match ] ) ) {
 this[ match ]( context[ match ] );

 // ...and otherwise set as attributes
 } else {
 this.attr( match, context[ match ] );
 }
 }
 }

 return this;

 // HANDLE: $(#id)
 } else {
 elem = document.getElementById( match[2] );

 // Check parentNode to catch when Blackberry 4.6 returns
 // nodes that are no longer in the document #6963
 if ( elem && elem.parentNode ) {
 // Handle the case where IE and Opera return items
 // by name instead of ID
 if ( elem.id !== match[2] ) {
 return rootjQuery.find( selector );
 }

 // Otherwise, we inject the element directly into the jQuery object
 this.length = 1;
 this[0] = elem;
 }

 this.context = document;
 this.selector = selector;
 return this;
 }

 // HANDLE: $(expr, $(...))
 } else if ( !context || context.jquery ) {
 return ( context || rootjQuery ).find( selector );

 // HANDLE: $(expr, context)
 // (which is just equivalent to: $(context).find(expr)
 } else {
 return this.constructor( context ).find( selector );
 }

 // HANDLE: $(DOMElement)
 } else if ( selector.nodeType ) {
 this.context = this[0] = selector;
 this.length = 1;
 return this;

 // HANDLE: $(function)
 // Shortcut for document ready
 } else if ( jQuery.isFunction( selector ) ) {
 return typeof rootjQuery.ready !== "undefined" ?
 rootjQuery.ready( selector ) :
 // Execute immediately if ready is not present
 selector( jQuery );
 }

 if ( selector.selector !== undefined ) {
 this.selector = selector.selector;
 this.context = selector.context;
 }

 return jQuery.makeArray( selector, this );
 }

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

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

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

  • 方式1. $(‘.parent .child'); 走完流程花费的时间:a;
  • 方式3. $(‘.child','.parent'); 走完流程花费的时间:a; 几乎已经找到dom节点
  • 方式1. $(‘.parent .child'); sizzle相关查找选择器.parent .child花费的时间:b;
  • 所以得出初步结论:
  • 方式3. $(‘.child','.parent');花费的时间:a;
  • 方式1. $(‘.parent .child');花费的时间:a + b;
  • 方式3优于方式1

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

jQuery查找dom的几种方法效率详解

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

jQuery查找dom的几种方法效率详解

接下来我们我们加入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的具体内容:

find: function( selector ) {
 var i,
 ret = [],
 self = this,
 len = self.length;

 if ( typeof selector !== "string" ) {
 return this.pushStack( jQuery( selector ).filter(function() {
 for ( i = 0; i < len; i++ ) {
  if ( jQuery.contains( self[ i ], this ) ) {
  return true;
  }
 }
 }) );
 }

 for ( i = 0; i < len; i++ ) {
 jQuery.find( selector, self[ i ], ret );
 }

 // Needed because $( selector, context ) becomes $( context ).find( selector )
 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
 ret.selector = this.selector ? this.selector + " " + selector : selector;
 return ret;
 }

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

jQuery查找dom的几种方法效率详解

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

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

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

jQuery查找dom的几种方法效率详解

总结

好了,以上就是这篇文文章的全部内容了,写到这里,突然感觉好像对自己并没有什么(luan)用,写的好像我的编码能力已经强到了来拼dom查找效率的地步 。希望能对有需要的朋友们有一定的帮助吧。

jQuery 相关文章推荐
jquery插件制作 自增长输入框实现代码
Aug 17 jQuery
jQuery插件FusionCharts绘制ScrollColumn2D图效果示例【附demo源码下载】
Mar 22 jQuery
jQuery中的deferred对象和extend方法详解
May 08 jQuery
jQuery滑动到底部加载下一页数据的实例代码
May 22 jQuery
jQuery Position方法使用和兼容性
Aug 23 jQuery
jQuery实现遍历XML节点和属性的方法示例
Apr 29 jQuery
jQuery中元素选择器(element)简单用法示例
May 14 jQuery
jquery ajax加载数据前台渲染方式 不用for遍历的方法
Aug 09 jQuery
jquery判断滚动条距离顶部的距离方法
Sep 05 jQuery
jquery.pager.js实现分页效果
Jul 29 jQuery
jQuery实现的图片点击放大缩小功能案例
Jan 02 jQuery
jQuery实现移动端笔触canvas电子签名
May 21 jQuery
jQuery实现div跟随鼠标移动
Aug 20 #jQuery
jquery+ajax实现省市区三级联动 (封装和不封装两种方式)
May 15 #jQuery
Jquery把获取到的input值转换成json
May 15 #jQuery
jQuery实现radio第一次点击选中第二次点击取消功能
May 15 #jQuery
jQuery返回定位插件详解
May 15 #jQuery
jQuery操作css样式
May 15 #jQuery
jQuery插件FusionCharts绘制的2D条状图效果【附demo源码】
May 13 #jQuery
You might like
PHP初学者头疼问题总结
2006/10/09 PHP
PHP编程之高级技巧——利用Mysql函数
2006/10/09 PHP
CI框架中集成CKEditor编辑器的教程
2014/06/09 PHP
php生成二维码
2015/08/10 PHP
JS getMonth()日期函数的值域是0-11
2010/02/15 Javascript
javascript笔记 String类replace函数的一些事
2011/09/22 Javascript
JQuery+Ajax无刷新分页的实例代码
2014/02/08 Javascript
jquery判断浏览器后退时候弹出消息的方法
2014/08/11 Javascript
用javascript读取xml文件读取节点数据
2014/08/12 Javascript
Javascript中的高阶函数介绍
2015/03/15 Javascript
js鼠标按键事件和键盘按键事件用法实例汇总
2016/10/03 Javascript
详解windows下vue-cli及webpack 构建网站(三)使用组件
2017/06/17 Javascript
angular实现spa单页面应用实例
2017/07/10 Javascript
iSlider手机端图片滑动切换插件使用详解
2019/12/24 Javascript
微信小程序返回上一级页面的实现代码
2020/06/19 Javascript
antd配置config-overrides.js文件的操作
2020/10/31 Javascript
用python删除java文件头上版权信息的方法
2014/07/31 Python
Python程序中使用SQLAlchemy时出现乱码的解决方案
2015/04/24 Python
使用python求解二次规划的问题
2020/02/29 Python
如何用Python徒手写线性回归
2021/01/25 Python
详解Sticky Footer 绝对底部的两种套路
2017/11/03 HTML / CSS
CSS实现聊天气泡效果
2020/04/26 HTML / CSS
HTML5 Canvas 实现K线图的示例代码
2019/12/23 HTML / CSS
草莓网美国官网:Strawberrynet USA
2016/12/11 全球购物
英国最大的化装舞会服装网站:Fancydress.com
2017/08/15 全球购物
捷克家居装饰及图书音像购物网站:Velký košík
2018/04/16 全球购物
Sneaker Studio波兰:购买运动鞋
2018/04/28 全球购物
苹果台湾官网:Apple台湾
2019/01/05 全球购物
得到Class的三个过程是什么
2012/08/10 面试题
北京RT科技有限公司.net工程师面试题
2013/02/15 面试题
英语专业个人求职自荐信
2013/09/21 职场文书
市场营销专业自荐书
2014/06/10 职场文书
合作与交流自我评价
2015/03/09 职场文书
叶问观后感
2015/06/15 职场文书
高老头读书笔记
2015/06/30 职场文书
竞聘开场白方式有哪些?
2019/08/28 职场文书