【问题标题】:Why is $(div#id) slower than $(#id)?为什么 $(div#id) 比 $(#id) 慢?
【发布时间】:2013-04-02 17:18:00
【问题描述】:

除非我的测试有问题,否则当我在 Chrome 上运行这个 jsfiddle 时,$("#id") 选择器大约需要 11 毫秒,$(div#id) 选择器大约需要 56 毫秒。

$(document).ready(function(){
    startTime = new Date().getTime();
    for (i = 0; i < 10000; i++)
    {
        s = $("#idC12");
    }           
    $("#idResults").html("c12 by id only time: "+elapsedMilliseconds(startTime));

    startTime = new Date().getTime();
    for (i = 0; i < 10000; i++)
    {
        s = $("div#idC12");
    }           
    $("#classResults").html("c12 by tagname#id: "+elapsedMilliseconds(startTime));
});

function elapsedMilliseconds(startTime)
{
    var n = new Date();
    var s = n.getTime();
    var diff = s - startTime;
    return diff;
}

http://jsfiddle.net/MhWUc/

【问题讨论】:

  • 除了下面的非常好的答案,我想说,因为你应该在页面上有唯一的 ID,没有必要像 div#id 那样具体...

标签: javascript jquery performance google-chrome


【解决方案1】:

这是因为$("#id") 内部使用了原生的document.getElementById 函数,该函数使用从 id 到具有此 id 的(唯一)元素的映射链接。

以下是 jQuery 源码中的相关代码:

        // Easily-parseable/retrievable ID or TAG or CLASS selectors
        rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/
        ...
        // Speed-up: Sizzle("#ID")
        if ( (m = match[1]) ) {
            if ( nodeType === 9 ) {
                elem = context.getElementById( m );
                // 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, Opera, and Webkit return items
                    // by name instead of ID
                    if ( elem.id === m ) {
                        results.push( elem );
                        return results;
                    }
                } else {
                    return results;
                }
            } else {
                // Context is not a document
                if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
                    contains( context, elem ) && elem.id === m ) {
                    results.push( elem );
                    return results;
                }
            }

你会注意到:

  • 当正则表达式检测到#someId 表单时使用它
  • 任何提供的上下文都只会添加一个测试,并不会使其更快

请注意,在定义 CSS 规则或使用 document.querySelector 时,此规则在 jQuery 之外仍然适用:当您知道 id 时,没有什么比使用 document.getElementById 更快的了(除了缓存元素...)。

【讨论】:

  • 准备好了,开始吧!你赢了:)
  • 为此,$(div#id) 必须在 div 上运行一个额外的选择器。我必须查看嘶嘶声引擎,看看是否首先查找并检查了 $(#id) 以确保 div-ness,但我想 ir 首先运行 querySelectAll(div),然后检查 id。跨度>
  • 有时我会忘记我为什么使用 jQuery,然后我看到其中的一些 cmets 并记住了原因。这是一个黑暗,黑暗的世界……
  • 同样,虽然id 属性应该在 HTML 文档中是唯一的,否则 $("#id")返回第一个与id 匹配的元素,就像getElementById() 一样。但是$("*#id") 将返回所有满足条件的内容。
【解决方案2】:

自从我进入源代码以来已经有一段时间了,但我知道 #some-id 选择器过去由 document.getElementById() 处理,而更复杂的选择器(例如,tagName#some-id)必须经过嘶嘶声并最终通过document.querySelectorAll.

【讨论】:

    【解决方案3】:

    $('div#id') 较慢,因为它不直接映射到本机 getElementById() 方法。

    【讨论】:

      【解决方案4】:

      当你使用 div#id 时,首先选择所有的 div。

      当你使用#id时,它会直接进入ids表。

      【讨论】:

      • 在底层不是还是从右到左的实现吗?
      • @jmar777 我不这么认为。我认为这就是 CSS 的工作方式,而不是 jQuery 的选择过程。我发誓我刚刚读过一些关于这个的东西。也许我错了。我去找找
      • @jmar777 或者,它可能是一种特殊情况,即 jQuery 在字符串中的任意位置查找 #,然后将调用直接映射到 getElementById 而不是仅仅将其传递给 querySelectorAll
      • 从右到左?在容器中获取特定项目之前是否需要在左侧获取容器......在右侧?也许在使用组合选择器时,即 withspace/comma 运算符。
      • @Ian 我认为该线程更适合#foo .bar 样式选择器,然后是.foo#bar。并且提供的源中的正则表达式与tagName#id 选择器不匹配。但是,您可能对仅在“组”级别应用的从右到左是正确的。想我可能需要在那个方面再深入一些......
      猜你喜欢
      • 2012-02-14
      • 1970-01-01
      • 2011-04-22
      • 2011-11-26
      • 2011-03-23
      • 1970-01-01
      相关资源
      最近更新 更多