javascript - jQuery 上下文会减慢搜索速度

标签 javascript jquery performance jquery-selectors jquery-context

这个问题在这里已经有了答案:




8年前关闭。




Possible Duplicate:
Performance of jQuery selector with context



jQuery DOCS它说

By default, selectors perform their searches within the DOM starting at the document root. However, an alternate context can be given for the search by using the optional second parameter to the $() function.



基于此,我的理解是使用 context 的选择作为第二个参数传入的应该比没有 context 的相同选择更快通过了。但是我进行了一些测试,似乎情况并非如此,或者至少并非总是如此。

详细地说,我最初想看看一次搜索多个元素( $("div1, #div2") )是否比单独搜索两个元素( $("#div1") $("div2") )更快。然后我决定用 context 测试它并且没有看到使用 context 的速度有多快,但当发现 context 时感到惊讶似乎放慢了速度。

例如,给出以下基本 HTML 标记
<div id="testCnt">
    <div id="Div0"></div>
    <div id="Div1"></div>
    <div id="Div2"></div>
    <div id="Div3"></div>
    <div id="Div4"></div>
    <div id="Div5"></div>
    <div id="Div6"></div>
    <div id="Div7"></div>
    <div id="Div8"></div>
    <div id="Div9"></div>
</div>

以及以下 JavaScript(jQuery 1.8.2,并使用 FireBug 进行测试)
$(function () {    
    var $dvCnt = $('#testCnt');
    var dvCnt = $dvCnt[0];

    console.time('Individual without cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0').text('Test');
        $('#Div1').text('Test');
        $('#Div2').text('Test');
        $('#Div3').text('Test');
        $('#Div4').text('Test');
        $('#Div5').text('Test');
        $('#Div6').text('Test');
        $('#Div7').text('Test');
        $('#Div8').text('Test');
        $('#Div9').text('Test');

    }
    console.timeEnd('Individual without cache');

    console.time('Individual with $cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0', $dvCnt).text('Test');
        $('#Div1', $dvCnt).text('Test');
        $('#Div2', $dvCnt).text('Test');
        $('#Div3', $dvCnt).text('Test');
        $('#Div4', $dvCnt).text('Test');
        $('#Div5', $dvCnt).text('Test');
        $('#Div6', $dvCnt).text('Test');
        $('#Div7', $dvCnt).text('Test');
        $('#Div8', $dvCnt).text('Test');
        $('#Div9', $dvCnt).text('Test');

    }
    console.timeEnd('Individual with $cache');

    console.time('Individual with DOM cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0', dvCnt).text('Test');
        $('#Div1', dvCnt).text('Test');
        $('#Div2', dvCnt).text('Test');
        $('#Div3', dvCnt).text('Test');
        $('#Div4', dvCnt).text('Test');
        $('#Div5', dvCnt).text('Test');
        $('#Div6', dvCnt).text('Test');
        $('#Div7', dvCnt).text('Test');
        $('#Div8', dvCnt).text('Test');
        $('#Div9', dvCnt).text('Test');

    }
    console.timeEnd('Individual with DOM cache');


    console.time('Multiple without cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0,#Div1 ,#Div2 ,#Div3 ,#Div4 ,#Div5 ,#Div6, #Div7, #Div8, #Div9').text('Test');
    }
    console.timeEnd('Multiple without cache');

    console.time('Multiple with $cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0,#Div1 ,#Div2 ,#Div3 ,#Div4 ,#Div5 ,#Div6, #Div7, #Div8, #Div9', $dvCnt).text('Test');
    }
    console.timeEnd('Multiple with $cache');

    console.time('Multiple with DOM cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0,#Div1 ,#Div2 ,#Div3 ,#Div4 ,#Div5 ,#Div6, #Div7, #Div8, #Div9', dvCnt).text('Test');
    }
    console.timeEnd('Multiple with DOM cache');
});

这是一个 jsbin

我得到如下结果

个人无缓存:11490ms
有 $cache 的个人:13315ms
有 DOM 缓存的个体:14487ms

多个无缓存:7557ms
多个 $cache: 7824ms
多个 DOM 缓存:8589ms

有人可以对发生的事情有所了解吗?具体为什么在传入 jQuery 上下文时搜索会变慢?

编辑:

这里的大多数回答者(以及 Performance of jQuery selector with context )基本上都说这个例子中的 DOM 太小而不能真正获得太多,或者通过 ID 选择无论如何都会很快。我理解这两点,我的问题的重点是为什么 context 向下搜索,大小DOM不应该对此产生影响,按 ID 搜索已经非常快的事实也不应该有什么不同。

@pebble建议它较慢的原因是因为 jQuery 不能使用 native 浏览器方法( getElementByID ),这对我来说似乎很有意义,但是为什么在一个选择中搜索多个元素会更快?

无论如何,我将测试转储到 jsPerf添加案例以按类搜索,再次惊讶地发现这次搜索多个带有缓存的类是最快的。

最佳答案

我想在很多情况下使用上下文会减慢速度,主要是因为 jQuery 会尝试使用浏览器 native 方法,而不是遍历整个 dom。一个例子是使用 document.getElementById就像你的例子一样。

为什么变慢了?
getElementById仅存在于文档对象上 - 您无法在上下文元素上使用它 - 即 element.getElementById .所以我的理论是 jQuery 首先使用 document.getElementById 进行 id 请求。 ,然后,如果有上下文集 - 扫描每个元素的父元素以判断它们中是否有任何作为上下文的子元素存在 - 从而减慢进程。

其他可能很慢的选择器示例

您还会发现其他地方,根据您使用的选择器,您将获得性能提升 - 一切都取决于 jQuery 可以使用哪些方法来加速它的工作。例如:

$('.className');

很可能会转化为使用 getElementsByClassName或通过 className 提供的任何其他本地方法进行选择,但是:
$('.className .anotherClassName');

不能使用它(因为它必须考虑到关系)并且必须使用 querySelector 的混合物。 (如果存在)和或纯 javascript 逻辑来解决问题。

充分了解可用的 native 方法将帮助您优化 jQuery 查询。

优化方法

如果您希望使用上下文进行优化,我想这将证明比不使用时查询更快:
$('div', context);

这是因为 getElementsByTagName从一开始就已经存在一段时间了,并且可以在纯 JavaScript 中直接在 DOM 元素上使用。但是,如果您要这样做,执行以下操作可能会更快:
$().pushStack( context[0].getElementsByTagName('div') );


$( context[0].getElementsByTagName('div') );

主要是因为您减少了 jQuery 函数调用,尽管这不是那么简洁。关于许多流行的 JavaScript 环境需要注意的另一件事 - 调用不带参数的函数比使用调用要快得多。

优化某些 jQuery 选择器的一个相对未使用的方法是使用 jQuery eq伪选择器 - 这可以以类似于使用 LIMIT 0,1 的方式加快速度。在 SQL 查询中 - 例如:
$('h2 > a');

将扫描所有 H2 以查找 A 元素,但是如果您从一开始就知道 H2 中只会有一个 A 标签,您可以这样做:
$('h2 > a:eq(0)');

另外,如果你知道只有一个 H2——逻辑是一样的:
$('h2:eq(0) > a:eq(0)');

$().pushStack 和 $().add 的区别

为了回应 Jasper 的评论,这里是两个函数之间的区别:

.add:
function (a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?
[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?
d:p.unique(d))}

.pushStack:
function (a,b,c){var d=p.merge(this.constructor(),a);return
d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector
+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d}

主要区别在于.add()用途 .pushStack()实现它的目标 - 添加允许支持更多的数据类型 - 甚至 jQuery 对象。而.pushStack仅适用于 DOM 元素,如果您使用的是 DOM 元素,则它会更加优化:)

通过 ID 进行选择的更快方法?

这是显而易见的,但我想我会把它放在这里,因为有时会遗漏一些东西 - 通过 id 选择元素的更快方法是执行以下操作:
$(document.getElementById('id'));

一切都是因为 jQuery/Sizzle 无法胜过 native 方法,这也意味着您可以避免在 jQuery/Sizzle 部分进行任何字符串解析。虽然它远不如它的 jQuery 对应物那么简洁,并且可能不会获得那么多的速度提升,但作为优化值得一提。如果您经常使用 id,您可以执行以下操作。
jQuery.byid = function(id){
  return jQuery(document.getElementById(id))
};

$.byid('elementid');

上面的代码会比我之前的示例稍微慢一点,但仍然应该胜过 jQuery。

关于javascript - jQuery 上下文会减慢搜索速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13057781/

相关文章:

jquery - 如何调整克隆的 jQuery UI 元素(图像)的大小

jquery - 嵌套 Jquery 调用

javascript - 按下按钮后如何访问网页的HTML

javascript - 正则表达式拆分 - 一次有效

jQuery Validate - 如何删除特定标签上的错误类?

c# - 尽管 PerformanceCounter 类别存在,但它并不存在

java - Android:运行一个空方法会产生多少开销?

iphone - 在 Xcode/Iphone 中测量 FPS/性能

php - 在 js 变量中发送 XML

javascript - Three.js - 移除 ArrowHelper 的头部