jQuery选择器的速度似乎是我的代码错误

时间:2015-06-02 20:29:38

标签: javascript jquery optimization jquery-selectors

我正在优化一些代码,我需要在下拉列表选择菜单中禁用第一个选项。我正在比较三种方法来找到最快的方法,所有方法都可以在这里找到jquery-fastest-method-find-descendents

他们是:

1. Scope:  $(".child", $("#parent"));
2. Find: $("#parent").find(".child"); 
3. 'Normal': $("#parent .child"); 
(I call it 'Normal' because that's the one I normally use for everything)

根据链接文章和其他SO帖子,我看到1和2应该是相同的,那么3应该是最慢的。然而,我操纵了一个小小的时间小提琴,它似乎显示完全相反。

Fiddle Here

对于三个测试中的每一个,小提琴创建1000个选择菜单,每个菜单给它们10个选项,并给随机选择菜单禁用我类(我想要一些变化来看它是否改变了结果)。然后计时器开始,jquery选择器进入并找到.disableMe并禁用第一个选项。

所以有人能告诉我为什么我看到了我所期待的相反结果?我是否在测试的时间部分搞砸了某些东西,或者某些高级逻辑被弄糊涂了?

那些不想要小提琴的人的代码:

function createMenus()
{
    $('body').empty();
    for (var i = 0; i < 1000; i++)
    {
         var select = $(document.createElement('select')).appendTo($('body'));
         if( Math.round(Math.random() * 1))
               select.addClass("disableMe");
         for (var j = 0; j < 10; j++)
         {   
             $(document.createElement('option')).appendTo(select).html('optionText');
         }
    }
}

//.find()
createMenus();
var start= Date.now();
$('.disableMe').find('option:nth-child(1)').attr('disabled', 'disabled');
var diff = Date.now() - start;
console.log("Find: "+ diff )

//Normal selector
createMenus();
start= Date.now();
$('.disableMe option:nth-child(1)').attr('disabled', 'disabled');
diff = Date.now() - start;
console.log("'Normal': "+ diff )

//Scope selector
createMenus();
start= Date.now();
$('option:nth-child(1)', '.disableMe').attr('disabled', 'disabled');
diff = Date.now() - start;
console.log("Scope: "+ diff )

我看到的平均结果:

 Find: 20
 'Normal': 4
 Scope: 16

3 个答案:

答案 0 :(得分:2)

本文假设jQuery必须使用Sizzle库来解析和执行选择器。现代浏览器已不再适用。

大多数选择器(使用jQuery扩展的选择器除外)都可以使用querySelectorAll方法执行。由于它内置于浏览器中,因此比前两种选择更快。

所有常见浏览器的当前版本都支持querySelectorAll方法,并且早在IE 9中。

除非您有任何实际的性能问题,否则您应该选择最简单的解决方案。本文中的建议就是一个很好的例子,说明当浏览器实现发生变化时,微优化代码会如何适得其反。

答案 1 :(得分:2)

这是非常主观的。选择器速度优化严重依赖浏览器。你引用的帖子是从IE7 / 8仍然相关的时间开始的。甚至IE6也可能与某些人有关。

差异有几个:

  1. 浏览器没有querySelector / querySelectorAll - 然后解析表达式并将其细分为有效的位,例如document.getElementByIddocument.getElementsByClassName(如果可用),document.getElementsByTagName - 然后应用适当的过滤器,例如仅选择第n个类型的结果等。这通常涉及多个正则表达式和函数调用。

  2. 浏览器确实有querySelectorAll - 所有常青供应商都对其进行了大量优化。鉴于该表达式没有任何伪表达式,如:is:not:has,它将是一个直接传递。

  3. 你可以在你的小提琴上测试这个 - http://fiddle.jshell.net/shewhqc4/show/light/

    打开控制台并使用:

    console.time('select');
    console.log($$('.disableMe option:nth-child(1)'));
    console.timeEnd('select');
    
    console.time('selectJQ');
    console.log($('.disableMe option:nth-child(1)'));
    console.timeEnd('selectJQ');
    

    第一个是QSA,第二个是jQuery - 在我的FF上慢了大约8-9ms。

    其他方法在常绿浏览器上运行速度较慢的原因是因为它们不是最常用的用例代码路径(第一个),其次,它们需要chain结果并传递上下文以便进行更多的函数调用。

    最终,选择器速度是一个毫无意义的衡量标准,因为它不可能不断地搜索整个dom w / o缓存结果,除非你正在编写游戏,否则收益将毫无意义。

答案 2 :(得分:0)

您可以打开Chrome的Developer Tools,然后在Profiles菜单中收集新的JavaScript CPU Profile。收集数据后,点击Heavy (Bottom Up)并将其更改为Chart,然后您就可以轻松了解消耗更多时间的内容。