1

我很好奇浏览器查找哪个选择器会更快。我对一般浏览器而不是特定浏览器感兴趣。

$('accountDetailsTable').getElements('.toggler')

这将accountDetailsTable像您正在使用一样document.getElementById('accountDetailsTable');查找,然后.toggler在元素内部查找。

$$('.toggler')

而这个将直接返回所有选择器。但最终他们都会给我同样的结果。

那么哪一个会更快呢?我怎么能测试这个?

4

2 回答 2

5

选择器的性能在浏览器之间会有很大差异。例如。有querySelectorquerySelectorAll(QSA)与没有。没有 QSA 时,有getElementsByClassName或没有。

选择器引擎需要做的工作量会有所不同。

你可以用不同的方式写这个。3 种方法,而不仅仅是 2 种:

1.$('accountDetailsTable').getElements('.toggler')

上面的解剖是:

  • 获取元素(1 次调用)。
  • 从元素原型(或直接在旧 IE 中的元素)调用 getElements 方法
  • 查找与类选择器匹配的所有子节点

这在浏览器中是一致的,因为它获取一个根节点并调用它的方法。如果没有 QSA,它将去getElementsByClassName或遍历所有childNodes并过滤className属性,直到它有一个匹配列表。性能方面,这在现代浏览器中会更糟,因为它需要链接,而方法 3 将是直接结果。

因为选择器在 JS 中是如何工作的,与 CSS 不同——它是从左到右的,更多合格的选择器可以提高性能,这.toggler意味着当有一个较旧的浏览器时,它不需要考虑树中的每个 DOM 节点(文本除外节点)。尽可能地限定选择器,即div.togglera.toggler.

2.$$('.toggler')

  • 如果 QSA 可用,请依靠浏览器返回内容(这里没有额外的 hack,例如:not, or :containsor :hasor !(反向组合符)。
  • 如果没有 QSA,它将通过 Slick 解析器解析表达式,并基本上在内部降级为类似于上述情况 1 的内容。这里最大的区别是缺少上下文——它将针对整个文档运行,因为 $$ 内部会执行类似的操作document.getElements('.toggler'),因此需要考虑更多节点。始终将您的查询锚定到一个稳定的最常见的节点。或将其传递到查询字符串中以进行限定,如案例 3

再一次,这将通过使其更合格来提高性能,例如:

$$('a.toggler')

3.$$('#accountDetailsTable .toggler')

  • 与案例 2 类似,但当 QSA 可用时,它会更快。
  • 当 QSA 不存在时,它将针对 #accountDetailsTable 节点的上下文运行,因此它会比情况 2 更好。

使这更合格将有所作为:

$$('#accountDetailsTable td.control > a.toggler')

大折扣:这取决于您的 DOM 有多大,找到并返回了多少匹配项。在简单的 DOM 上,预期的性能顺序可能会有所不同。

如今,选择器的性能优化越来越无关紧要。

SlickText 比较框架的时代已经结束,应用程序性能与选择器速度几乎没有关系,或者您做错了什么。

如果你的工作做得对,你就不需要不断地选择元素。您可以缓存东西、重用、智能并将 DOM 查找减少到最低限度。

事件等可以通过智能事件委托附加,在适当的情况下,完全不需要选择和添加事件到多个节点等 - 使用常识,不要挂在理论性能基准上。相反,请使用分析器并测试您的实际应用程序,看看您在哪里浪费时间/CPU 周期。

您可以在一秒钟内运行这样一个简单的选择器超过 50000 次。这是微基准测试,并不能衡量您的 APP、DOM、浏览器等内部的实际性能。

关于基准测试性能和过早优化的更多想法:http ://www.youtube.com/watch?v=65-RbBwZQdU

小心

首先写正确性和可读性。即使你可以通过做某事获得额外的性能,如果它不是关键/一直重用,也不要以牺牲可读性为代价。像.toggler,.new等选择器.button往往过于通用,并且可以在 DOM 的不同部分的应用程序中重用。您需要限定选择器以确保您的预期功能在移动到不同的页面/小部件/DOM 并且您的项目获得新开发人员涌入时继续工作。

只是我的两分钱,我知道你已经接受了答案。

于 2013-11-06T14:36:27.547 回答
1

在过去的两年里,我对 MooTools 的内部知识有点生疏,但总的来说,我希望$$-selector 更快,因为它只需要遍历元素一次。

为什么不试试呢?看到这个 JSfiddle

粗略的 HTML:

<div id="accountDetailsTable">
    <div id=".toggler">1</div>    
    <div id=".toggler">2</div>    
    <div id=".toggler">3</div>    
</div>

JScript(请不要评论糟糕的代码,它只是为了演示功能):

window.addEvent('domready', function() { 
    var iter = 50000;

    var tstart = new Date().getTime();
    for (var i=0;i<iter;i++) {
        var x = $('accountDetailsTable').getElements('.toggler');
    }

    var tend = new Date().getTime();   
    var tdur = tend - tstart;

    console.log('$: ' + tdur + ' ms');

    var tstart = new Date().getTime();
    for (var i=0;i<iter;i++) {
         var x = $$('.toggler');
    }

    var tend = new Date().getTime();   
    var tdur = tend - tstart;

    console.log('$$: ' + tdur + ' ms');
});

也就是说,我进行了大约 50000 次迭代的测试大致得出了以下结果:

  • $('accountDetailsTable').getElements('.toggler'): ~ 4 秒
  • $$('.toggler'): ~ 2 秒

结果会因浏览器、元素等而异,因此这只是一个粗略的近似值。

这就是说,如果您在这么短的时间内拥有那么多选择器,您可能只会感觉到不同。是的,应该考虑性能,如果您的应用程序中只有几个选择器,那么这并不重要。

我更喜欢$$(),不是因为更好的性能,而是因为更好的可读性。

于 2013-11-06T13:22:26.120 回答