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平滑滚动到顶部插件使用详解
May 08 jQuery
jQuery 循环遍历改变a标签的href(实例讲解)
Jul 12 jQuery
jQuery插件jsonview展示json数据
May 26 jQuery
jQuery实现导航样式布局操作示例【可自定义样式布局】
Jul 24 jQuery
jQuery pjax 应用简单示例
Sep 20 jQuery
Jquery的Ajax技术使用方法
Jan 21 jQuery
JQuery中queue方法用法示例
Jan 31 jQuery
如何使用CSS3和JQuery easing 插件制作绚丽菜单
Jun 18 jQuery
jquery分页优化操作实例分析
Aug 23 jQuery
jquery绑定事件 bind和on的用法与区别分析
May 22 jQuery
jQuery+ThinkPHP实现图片上传
Jul 23 jQuery
jQuery列表动态增加和删除的实现方法
Nov 05 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
教你IIS6的PHP最佳配置方法
2006/09/05 PHP
Thinkphp事务操作实例(推荐)
2017/04/01 PHP
php接口实现拖拽排序功能
2018/04/23 PHP
Javascript延迟执行实现方法(setTimeout)
2010/12/30 Javascript
jQuery中height()方法用法实例
2014/12/24 Javascript
jQuery EasyUI datagrid实现本地分页的方法
2015/02/13 Javascript
JS访问SWF的函数用法实例
2015/07/01 Javascript
跟我学习javascript创建对象(类)的8种方法
2015/11/20 Javascript
onmouseover事件和onmouseout事件全面理解
2016/08/15 Javascript
jQuery焦点图轮播效果实现方法
2016/12/19 Javascript
基于pako.js实现gzip的压缩和解压功能示例
2017/06/13 Javascript
基于jQuery的左滑出现删除按钮的示例
2017/08/29 jQuery
小程序关于请求同步的总结
2019/05/05 Javascript
基于Vue SEO的四种方案(小结)
2019/07/01 Javascript
关于JS模块化的知识点分享
2019/10/16 Javascript
JS使用setInterval计时器实现挑战10秒
2020/11/08 Javascript
Python获取远程文件大小的函数代码分享
2014/05/13 Python
在Python中执行系统命令的方法示例详解
2017/09/14 Python
Python读取本地文件并解析网页元素的方法
2018/05/21 Python
Python多进程池 multiprocessing Pool用法示例
2018/09/07 Python
python创建文件备份的脚本
2018/09/11 Python
用Pytorch训练CNN(数据集MNIST,使用GPU的方法)
2019/08/19 Python
在Mac中PyCharm配置python Anaconda环境过程图解
2020/03/11 Python
Python定义一个函数的方法
2020/06/15 Python
Python爬虫实例——爬取美团美食数据
2020/07/15 Python
Python函数__new__及__init__作用及区别解析
2020/08/31 Python
Hertz荷兰:荷兰和全球租车
2018/01/07 全球购物
LN-CC日本:高端男装和女装的奢侈时尚目的地
2019/09/01 全球购物
企业员工爱岗敬业演讲稿
2014/08/26 职场文书
业务员工作态度散漫检讨书
2014/11/02 职场文书
运动员入场词
2015/07/18 职场文书
幼儿园大班开学寄语(2016秋季)
2015/12/03 职场文书
2017元旦、春节期间廉洁自律承诺书
2016/03/25 职场文书
JavaScript 定时器详情
2021/11/11 Javascript
世界无敌的ICOM IC-R9500宽频接收机
2022/03/25 无线电