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仿京东商品放大浏览页面
Jun 06 jQuery
jQuery为某个div加入行样式
Jun 09 jQuery
JQuery form表单提交前验证单选框是否选中、删除记录时验证经验总结(整理)
Jun 09 jQuery
jQuery动态添加.active 实现导航效果代码思路详解
Aug 29 jQuery
jQuery选择器中的特殊符号处理方法
Sep 08 jQuery
jQuery 导航自动跟随滚动的实现代码
May 30 jQuery
jQuery属性选择器用法实例分析
Jun 28 jQuery
jQuery中DOM常见操作实例小结
Aug 01 jQuery
JQuery实现ul中添加LI和删除指定的Li元素功能完整示例
Oct 16 jQuery
jQuery实现可编辑的表格
Dec 11 jQuery
jQuery实现html可联动的百分比进度条
Mar 26 jQuery
jquery实现抽奖功能
Oct 22 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开发GUI
2006/10/09 PHP
PHP学习笔记之数组篇
2011/06/28 PHP
php实现可逆加密的方法
2015/08/11 PHP
写自已的js类库需要的核心代码
2012/07/16 Javascript
在NodeJS中启用ECMAScript 6小结(windos以及Linux)
2014/07/15 NodeJs
防止登录页面出现在frame中js代码
2014/07/22 Javascript
Node.js中使用事件发射器模式实现事件绑定详解
2014/08/15 Javascript
JavaScript中创建字典对象(dictionary)实例
2015/03/31 Javascript
快速学习jQuery插件 Form表单插件使用方法
2015/12/01 Javascript
node.js中的事件处理机制详解
2016/11/26 Javascript
详解本地Node.js服务器作为api服务器的解决办法
2017/02/28 Javascript
jQuery插件jqGrid动态获取列和列字段的方法
2017/03/03 Javascript
BootStrap的双日历时间控件使用
2017/07/25 Javascript
浅谈在vue中用webpack打包之后运行文件的问题以及相关配置方法
2018/02/21 Javascript
Vue中的v-for指令不起效果的解决方法
2018/09/27 Javascript
Vue 中使用富文本编译器wangEditor3的方法
2019/09/26 Javascript
使用vue打包进行云服务器上传的问题
2020/03/02 Javascript
微信小程序自定义navigationBar顶部导航栏适配所有机型(附完整案例)
2020/04/26 Javascript
Python 包含汉字的文件读写之每行末尾加上特定字符
2016/12/12 Python
让Django支持Sql Server作后端数据库的方法
2018/05/29 Python
Python numpy实现二维数组和一维数组拼接的方法
2018/06/05 Python
Python使用while循环花式打印乘法表
2019/01/28 Python
tensorflow2.0教程之Keras快速入门
2021/02/20 Python
html5服务器推送_动力节点Java学院整理
2017/07/12 HTML / CSS
Darphin迪梵官网: 来自巴黎,植物和精油调制的护肤品牌
2016/10/11 全球购物
Missguided美国官网:英国时尚品牌
2018/01/18 全球购物
现代家居用品及礼品:LBC Modern
2018/06/24 全球购物
师范生实习个人的自我评价
2013/09/28 职场文书
元宵节主持词
2014/03/25 职场文书
报告会主持词
2014/04/02 职场文书
2014机关干部学习“焦裕禄精神”思想汇报
2014/09/19 职场文书
中学生自我评价2015
2015/03/03 职场文书
建国大业电影观后感
2015/06/01 职场文书
React Hook用法示例详解(6个常见hook)
2021/04/28 Javascript
Pytorch中的数据集划分&正则化方法
2021/05/27 Python
python析构函数用法及注意事项
2021/06/22 Python