怎样才能高效地使用jquery

李慕白 李慕白     2022-09-16     106

关键词:

1. 使用最新版本的jQuery

jQuery的版本更新很快,你应该总是使用最新的版本。因为新版本会改进性能,还有很多新功能。下面就来看看,不同版本的jQuery性能差异有多大。这里是三条最常见的jQuery选择语句:

1
2
3
$(‘.elem‘)
$(‘.elem‘, context)
context.find(‘.elem‘)

我们用1.4.2、1.4.4、1.6.2三个版本的jQuery测试,看看浏览器在1秒内能够执行多少次。可以看到,1.6.2版本的运行次数,远远超过两个老版本。尤其是第一条语句,性能有数倍的提高。

其他语句的测试,比如.attr("value")和.val(),也是新版本的jQuery表现好于老版本。

2. 用对选择器

在jquery中,你可以用多种选择器,选择同一个网页元素。每种选择器的性能是不一样的,你应该了解它们的性能差异。

    1. 最快的选择器:id选择器和元素标签选择器

举例来说,下面的语句性能最佳:

1
2
3
$(‘#id‘)
$(‘form‘)
$(‘input‘)

遇到这些选择器的时候,jQuery内部会自动调用浏览器的原生方法(比如getElementById()),所以它们的执行速度快。

    1. 较慢的选择器:class选择器

$(‘.className‘)的性能,取决于不同的浏览器。 Firefox、Safari、Chrome、Opera浏览器,都有原生方法getElementByClassName(),所以速度并不慢。但是,IE5-IE8都没有部署这个方法,所以这个选择器在IE中会相当慢。

    1. 最慢的选择器:伪类选择器和属性选择器

先来看例子。找出网页中所有的隐藏元素,就要用到伪类选择器:$(‘:hidden‘),属性选择器的例子则是:$(‘[attribute=value]‘)。

这两种语句是最慢的,因为浏览器没有针对它们的原生方法。但是,一些浏览器的新版本,增加了querySelector()和querySelectorAll()方法,因此会使这类选择器的性能有大幅提高。

总之,性能来说,ID选择器遥遥领先,然后是标签选择器,第三是Class选择器,其他选择器都非常慢。

3. 理解子元素和父元素的关系

下面六个选择器,都是从父元素中选择子元素。你知道哪个速度最快,哪个速度最慢吗?

1
2
3
4
5
6
$(‘.child‘, $parent)
$parent.find(‘.child‘)
$parent.children(‘.child‘)
$(‘#parent > .child‘)
$(‘#parent .child‘)
$(‘.child‘, $(‘#parent‘))

我们一句句来看。

  • $(‘.child‘, $parent):这条语句的意思是,给定一个DOM对象,然后从中选择一个子元素。jQuery会自动把这条语句转成$.parent.find(‘child‘),这会导致一定的性能损失。它比最快的形式慢了5%-10%。
  • $parent.find(‘.child‘):这条是最快的语句。.find()方法会调用浏览器的原生方法(getElementById,getElementByName,getElementByTagName等等),所以速度较快。
  • $parent.children(‘.child‘):这条语句在jQuery内部,会使用$.sibling()和javascript的nextSibling()方法,一个个遍历节点。它比最快的形式大约慢50%。
  • $(‘#parent > .child‘):jQuery内部使用Sizzle引擎,处理各种选择器。Sizzle引擎的选择顺序是从右到左,所以这条语句是先选.child,然后再一个个过滤出父元素#parent,这导致它比最快的形式大约慢70%。
  • $(‘#parent .child‘):这条语句与上一条是同样的情况。但是,上一条只选择直接的子元素,这一条可以于选择多级子元素,所以它的速度更慢,大概比最快的形式慢了77%。
  • $(‘.child‘, $(‘#parent‘)):jQuery内部会将这条语句转成$(‘#parent‘).find(‘.child‘),比最快的形式慢了23%。

所以,最佳选择是$parent.find(‘.child‘)。而且,由于$parent往往在前面的操作已经生成,jQuery会进行缓存,所以进一步加快了执行速度。

4. 不要过度使用jquery

jQuery速度再快,也无法与原生的javascript方法相比。所以有原生方法可以使用的场合,尽量避免使用jQuery。

请看下面的例子,为a元素绑定一个处理点击事件的函数:

1
2
3
$(‘a‘).click(function(){
    alert($(this).attr(‘id‘));
});

这段代码的意思是,点击a元素后,弹出该元素的id属性。为了获取这个属性,必须连续两次调用jQuery,第一次是$(this),第二次是attr(‘id‘)。 事实上,这种处理完全不必要。更正确的写法是,直接采用javascript原生方法,调用this.id:

1
2
3
$(‘a‘).click(function(){
    alert(this.id);
});

根据测试,this.id的速度比$(this).attr(‘id‘)快了20多倍。

5. 做好缓存

选中某一个网页元素,是开销很大的步骤。所以,使用选择器的次数应该越少越好,并且尽可能缓存选中的结果,便于以后反复使用。

比如,下面这样的写法就是糟糕的写法:

1
2
jQuery(‘#top‘).find(‘p.classA‘);
jQuery(‘#top‘).find(‘p.classB‘);

更好的写法是:

1
2
3
varcached = jQuery(‘#top‘);
cached.find(‘p.classA‘);
cached.find(‘p.classB‘);

根据测试,缓存比不缓存,快了2-3倍。

6. 使用链式写法

jQuery的一大特点,就是允许使用链式写法。

1
$(‘div‘).find(‘h3‘).eq(2).html(‘Hello‘);

采用链式写法时,jQuery自动缓存每一步的结果,因此比非链式写法要快。根据测试,链式写法比(不使用缓存的)非链式写法,大约快了25%。

7. 事件的委托处理(EventDelegation)

javascript的事件模型,采用"冒泡"模式,也就是说,子元素的事件会逐级向上"冒泡",成为父元素的事件。 利用这一点,可以大大简化事件的绑定。比如,有一个表格(table元素),里面有100个格子(td元素),现在要求在每个格子上面绑定一个点击事件(click),请问是否需要将下面的命令执行100次?

1
2
3
$("td").bind("click", function(){
    $(this).toggleClass("click");
});

回答是不需要,我们只要把这个事件绑定在table元素上面就可以了,因为td元素发生点击事件之后,这个事件会"冒泡"到父元素table上面,从而被监听到。因此,这个事件只需要在父元素绑定1次即可,而不需要在子元素上绑定100次,从而大大提高性能。这就叫事件的"委托处理",也就是子元素"委托"父元素处理这个事件。

具体的写法有两种。第一种是采用.delegate()方法:

1
2
3
$("table").delegate("td","click", function(){
    $(this).toggleClass("click");
});

第二种是采用.live()方法:

1
2
3
4
5
$("table").each(function(){
    $("td", this).live("click",function(){
        $(this).toggleClass("click");
    });
});

这两种写法基本等价。唯一的区别在于,.delegate()是当事件冒泡到指定的父元素时触发,.live()则是当事件冒泡到文档的根元素后触 发,因此.delegate()比.live()稍快一点。此外,这两种方法相比传统的.bind()方法还有一个好处,那就是对动态插入的元素也有效,.bind()只对已经存在的DOM元素有效,对动态插入的元素无效。

根据测试,委托处理比不委托处理,快了几十倍。在委托处理的情况下,.delegate()又比.live()大约快26%。

8. 少改动DOM结构

改动DOM结构开销很大,因此不要频繁使用.append()、.insertBefore()和.insetAfter()这样的方法。如果要插入多个元素,就先把它们合并,然后再一次性插入。根据测试,合并插入比不合并插入,快了将近10倍。

如果你要对一个DOM元素进行大量处理,应该先用.detach()方法,把这个元素从DOM中取出来,处理完毕以后,再重新插回文档。根据测试,使用.detach()方法比不使用时,快了60%。

如果你要在DOM元素上储存数据,不要写成下面这样:

1
2
var elem = $(‘#elem‘);
elem.data(key,value);

而要写成:

1
2
var elem = $(‘#elem‘);
$.data(elem,key,value);

根据测试, 后一种写法要比前一种写法,快了将近10倍。因为elem.data()方法是定义在jQuery函数的prototype对象上面的, 而$.data()方法是定义jQuery函数上面的,调用的时候不从复杂的jQuery对象上调用,所以速度快得多。

9. 正确处理循环

循环总是一种比较耗时的操作,如果可以使用复杂的选择器直接选中元素,就不要使用循环,去一个个辨认元素。

javascript原生循环方法for和while,要比jQuery的.each()方法快,应该优先使用原生方法。

10. 尽量少生成jquery对象

每当你使用一次选择器(比如$(‘#id‘)),就会生成一个jQuery对象。jQuery对象是一个很庞大的对象,带有很多属性和方法,会占用不少资源。所以,尽量少生成jQuery对象。

举例来说,许多jQuery方法都有两个版本,一个是供jQuery对象使用的版本,另一个是供jQuery函数使用的版本。下面两个例子,都是取出一个元素的文本,使用的都是text()方法。你既可以使用针对jquery对象的版本:

1
2
var $text = $("#text");
var $ts = $text.text();

也可以使用针对jQuery函数的版本:

1
2
var $text = $("#text");
var $ts = $.text($text);

由于后一种针对jquery函数的版本不通过jQuery对象操作,所以相对开销较小,速度比较快。

我怎样才能简单地使用这种数字格式验证正则表达式?

】我怎样才能简单地使用这种数字格式验证正则表达式?【英文标题】:HowcanIsimplythisnumberformatvalidationregex?【发布时间】:2012-10-2916:48:32【问题描述】:所以,我有这个if语句:if(String(val).search(/^((\\d+(((\\,\\d3,)+)?)(\\.\\d+)?)|(\\.\\d+)... 查看详情

我怎样才能知道 GCC 可以使用哪些标志来更轻松地链接库?

】我怎样才能知道GCC可以使用哪些标志来更轻松地链接库?【英文标题】:HowcanIknowwhichflagsareavailableforGCCtolinklibrarymoreeasily?【发布时间】:2012-02-1805:01:25【问题描述】:在阅读有关某些库的文档时,我看到某些库具有某些功能,... 查看详情

MVC 中的 JQuery Ajax,将表单值传递给 Controller 方法。所有值都是空的,我怎样才能通过 jquery 正确地将表单值传递给控制器​​?

...yAjax,将表单值传递给Controller方法。所有值都是空的,我怎样才能通过jquery正确地将表单值传递给控制器​​?【英文标题】:JQueryAjaxinMVC,passingformvaluestoControllermethod.Allvaluesarenull,howcanIproperlypassformvaluesthroughjquerytoacontroller?【发... 查看详情

怎样高效地去判断array中是否包含某个值?

问题怎样去判断Array(无序)中是否包含某个值呢?这是一个在Java中经常被问到的问题。它也是StackOverflow上投票前几的一个问题。下面将展示投票前几的几个回答,这些回答使用不同的方式解决了这个问题,但是,时间复杂度... 查看详情

怎样高效地报告bug

SummaryThefirstaimofabugreportistolettheprogrammerseethefailurewiththeirowneyes.Ifyoucan‘tbewiththemtomakeitfailinfrontofthem,givethemdetailedinstructionssothattheycanmakeitfailforthemselves.Incasethe 查看详情

我怎样才能更好地存储变量?

】我怎样才能更好地存储变量?【英文标题】:HowcouldIstorethevariablesbetter?【发布时间】:2013-01-1305:32:12【问题描述】:这是我小组的项目:https://github.com/stuycs-ml7-projects/YAN-SHAN-PHAN-WU我们正在开发可以使用GPS将消息存储在位置的... 查看详情

我怎样才能更多地了解 Python 的内部结构? [关闭]

】我怎样才能更多地了解Python的内部结构?[关闭]【英文标题】:HowcanIlearnmoreaboutPython’sinternals?[closed]【发布时间】:2011-03-1822:16:14【问题描述】:我已经使用Python编程半年多了,我对Python内部结构更感兴趣,而不是使用Python来... 查看详情

使用jquery,我怎样才能找到一个图像是不是存在一个div中的某个属性?

】使用jquery,我怎样才能找到一个图像是不是存在一个div中的某个属性?【英文标题】:Usingjquery,howcanifindifanimageexistswithacertainattributethatiswithinadiv?使用jquery,我怎样才能找到一个图像是否存在一个div中的某个属性?【发布时间... 查看详情

我怎样才能更好地有条件地渲染我的组件?

】我怎样才能更好地有条件地渲染我的组件?【英文标题】:HowcanIbetterconditionallyrendermycomponents?【发布时间】:2022-01-1205:25:58【问题描述】:我有很多组件根据我用于游戏的不同状态进行渲染。我目前正在使用用&号检查状态... 查看详情

我怎样才能使它成为一个更好的递归动画 jQuery 脚本?

】我怎样才能使它成为一个更好的递归动画jQuery脚本?【英文标题】:HowcanImakethisabetterrecursiveanimatedjQueryscript?【发布时间】:2011-06-0819:45:30【问题描述】:这个想法是为云div设置动画,并让它永久地在水平方向上来回动画。这... 查看详情

我怎样才能做到这一点? - 动画报价 - JQuery

】我怎样才能做到这一点?-动画报价-JQuery【英文标题】:HowcanIdothis?-AnimateQuote\'s-JQuery【发布时间】:2012-02-1603:44:10【问题描述】:请看这张图片:我需要这样的东西,它会显示报价逐渐相互叠加。我不想使用flash,我想让客户... 查看详情

我怎样才能明智地处理版本控制和核心数据模型?

】我怎样才能明智地处理版本控制和核心数据模型?【英文标题】:HowcanIsanelyapproachversioncontrolandCoreDatamodels?【发布时间】:2010-06-3018:47:04【问题描述】:当我们使用git将CoreData模型文件置于版本控制之下时,我们总是很难合并... 查看详情

我怎样才能更早地呼叫运输人员?

】我怎样才能更早地呼叫运输人员?【英文标题】:HowcanIcallfortransportersearlier?【发布时间】:2019-08-1203:29:10【问题描述】:我有一个模型,它总共生成5个负载,每个负载每2秒生成一次。当5个货物等待运输时,仅调用1个运输机... 查看详情

我怎样才能顺序淡入几个div?

】我怎样才能顺序淡入几个div?【英文标题】:HowcanIsequentiallyfadeinseveraldivs?【发布时间】:2013-06-0100:39:00【问题描述】:我正在尝试使用jQuery创建一个顺序淡入淡出。本质上,当页面加载时,我希望三个词一个接一个地淡入。... 查看详情

MFC:我们怎样才能轻松地从 CTreeCtrl 切换到 CTreeView?

】MFC:我们怎样才能轻松地从CTreeCtrl切换到CTreeView?【英文标题】:MFC:HowcanweswitchfromCTreeCtrltoCTreeVieweasly?【发布时间】:2020-06-1011:00:51【问题描述】:我有一个图形MFC应用程序,它在历史上是使用CTreeCtrl开发的。我想添加一个CSp... 查看详情

我怎样才能有效地洗牌?

】我怎样才能有效地洗牌?【英文标题】:HowcanIshufflebitsefficiently?【发布时间】:2014-11-0305:48:32【问题描述】:我需要对一个16位无符号整数进行洗牌,使偶数索引位于低字节,奇数索引位于高字节。input:fedcba9876543210(contiguouslynu... 查看详情

我怎样才能实现像jQuery的slideDown一样的向下滑动效果,但只使用CSS?

】我怎样才能实现像jQuery的slideDown一样的向下滑动效果,但只使用CSS?【英文标题】:HowcanIachieveaslidedowneffectlikejQuery\'sslideDown,butonlyusingCSS?【发布时间】:2011-12-0203:02:03【问题描述】:CSS3动画存在问题。它们不支持“自动”高... 查看详情

我怎样才能始终如一地自动化,使用 TFS vNext 构建步骤,构建我们的开发团队使用 Visual Studio 工作的任何解决方案文件?

】我怎样才能始终如一地自动化,使用TFSvNext构建步骤,构建我们的开发团队使用VisualStudio工作的任何解决方案文件?【英文标题】:HowcanIconsistentlyautomate,usingTFSvNextbuildsteps,buildingwhateversolutionfilesourdevelopmentteamsgetworkingusingVisualStu... 查看详情