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和ajax代替iframe的方法(详解)
Apr 12 jQuery
jQuery Masonry瀑布流布局神器使用详解
May 25 jQuery
JavaScript之事件委托实例(附原生js和jQuery代码)
Jul 22 jQuery
快速掌握jquery分页插件jqPaginator的使用方法
Aug 09 jQuery
jQuery中图片展示插件highslide.js的简单dom
Apr 22 jQuery
解决jquery有正确返回值但不执行success函数的问题
Aug 20 jQuery
jquery实现动态添加附件功能
Oct 23 jQuery
jQuery+PHP实现上传裁剪图片
Jun 29 jQuery
jQuery实现的卷帘门滑入滑出效果【案例】
Feb 18 jQuery
jQuery实现可编辑的表格
Dec 11 jQuery
jQuery 选择器用法基础入门示例
Jan 04 jQuery
Jquery $.map使用方法实例详解
Sep 01 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
模板引擎smarty工作原理以及使用示例
2014/05/25 PHP
PHP抽奖算法程序代码分享
2015/10/08 PHP
Jquery ThickBox插件使用心得(不建议使用)
2010/09/08 Javascript
javascript当中的代码嗅探扩展原生对象和原型(prototype)
2013/01/11 Javascript
Javascript之this关键字深入解析
2013/11/12 Javascript
js 高效去除数组重复元素示例代码
2013/12/19 Javascript
JavaScript运行时库属性一览表
2014/03/14 Javascript
jquery插件validation实现验证身份证号等
2015/06/04 Javascript
jQuery实现Email邮箱地址自动补全功能代码
2015/11/03 Javascript
jquery自定义插件开发之window的实现过程
2016/05/06 Javascript
8 行 Node.js 代码实现代理服务器
2016/12/05 Javascript
JavaScript简单验证表单空值及邮箱格式的方法
2017/01/20 Javascript
利用Js+Css实现折纸动态导航效果实例源码
2017/01/25 Javascript
javascript实现圣旨卷轴展开效果(代码分享)
2017/03/23 Javascript
react中的ajax封装实例详解
2017/10/17 Javascript
详解vue.js数据传递以及数据分发slot
2018/01/20 Javascript
彻底理解js面向对象之继承
2018/02/04 Javascript
vue结合element-ui使用示例
2019/01/24 Javascript
JQuery的加载和选择器用法简单示例
2019/05/13 jQuery
详解mpvue中使用vant时需要注意的onChange事件的坑
2019/05/16 Javascript
bootstrap-paginator服务器端分页使用方法详解
2020/02/13 Javascript
[05:26]TI10典藏宝瓶套装外观展示
2020/07/03 DOTA
python实现将pvr格式转换成pvr.ccz的方法
2015/04/28 Python
Python中的pack和unpack的使用
2018/03/12 Python
Django + Uwsgi + Nginx 实现生产环境部署的方法
2018/06/20 Python
Python中分支语句与循环语句实例详解
2018/09/13 Python
python调用百度地图WEB服务API获取地点对应坐标值
2019/01/16 Python
python中数据库like模糊查询方式
2020/03/02 Python
Pycharm创建文件时自动生成文件头注释(自定义设置作者日期)
2020/11/24 Python
中国领先的专业家电网购平台:国美在线
2016/12/25 全球购物
微软台湾官方网站:Microsoft台湾
2018/08/15 全球购物
英国最大的在线快递公司之一:ParcelHero
2019/11/04 全球购物
行政总经理岗位职责
2013/12/05 职场文书
项目投资合作意向书
2014/07/29 职场文书
党的群众路线查摆剖析材料
2014/10/10 职场文书
Python中的turtle画箭头,矩形,五角星
2022/03/16 Python