【问题标题】:Speed of jQuery selector seems to be wrong my codejQuery 选择器的速度似乎是错误的我的代码
【发布时间】:2015-08-16 19:55:21
【问题描述】:

我正在优化一些需要禁用下拉选择菜单中的第一个选项的代码。我比较了三种方法来找到最快的一种,都可以在这里找到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

【问题讨论】:

  • 附带说明,这似乎是一个 "micro" 优化,因为我怀疑您的屏幕上有 1000 个选择菜单。您可能会发现这个 programmers.stackexchange.com 的答案很有趣,因为它讨论了这种优化级别可能出现的问题。

标签: javascript jquery optimization jquery-selectors


【解决方案1】:

这是非常主观的。选择器速度优化很大程度上依赖于浏览器。您引用的帖子来自 IE7/8 仍然相关的时间。甚至 IE6 也可能与某些人相关。

区别有几个:

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

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

你可以在你的小提琴上测试这个 - 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-9 毫秒。

其他方法在常青浏览器上会变慢的原因是因为它们不是最常见的用例代码路径(第一),第二,它们需要chain 结果并传递上下文以便更多的函数调用。

最终,选择器速度是一个毫无意义的衡量标准,因为很少需要连续搜索整个 dom 没有缓存结果,除非您正在编写游戏,否则这些收益将毫无意义。

【讨论】:

  • 这让我觉得,没有意识到这篇文章这么老了。以为我看到一些较新的参考资料说同样的,但也许不是。起初我预计收益会更显着,但后来它变成了一个关于为什么会发生这种情况的实验,我实际上不会为了这些最小的收益而回过头来重构。
【解决方案2】:

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

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

所有常见浏览器的当前版本都支持querySelectorAll 方法,并且可以追溯到IE 9。

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

【讨论】:

    【解决方案3】:

    您可以打开 Chrome 的Developer Tools 并在Profiles 菜单中收集一个新的JavaScript CPU Profile。收集好数据后,点击Heavy (Bottom Up),改成Chart,你就很容易知道什么东西比较耗时。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-22
      • 2018-08-10
      • 1970-01-01
      • 2012-12-27
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多