【问题标题】:jQuery - Select only the first element that matches for performancejQuery - 只选择第一个匹配性能的元素
【发布时间】:2014-11-26 20:46:44
【问题描述】:

是否可以编写一个只选择第一个符合条件的元素并停在那里的jQuery选择器?

我知道性能不佳的:first 选择器和更好的.first() 调用,但两者似乎都选择了所有元素,然后只返回[0] 位置的元素。

假设我在一个表中有 100 行,我需要对所有这些行做些什么。它们没有 ID,而是具有唯一值的 data-guid 属性。

这是一个带有列表的示例:

<ol>
    <li data-guid="guid_1">A</li>
    <li data-guid="guid_2">B</li>
    <li data-guid="guid_3">C</li>
    <li data-guid="guid_4">D</li>
</ol>

.

var data = [
    {guid: "guid_1", new_value: "I"},
    {guid: "guid_2", new_value: "II"},
    {guid: "guid_3", new_value: "III"},
    {guid: "guid_4", new_value: "IV"}
];

var $ol = $('#list');
for (var i = 0; i < data.length; ++i) {
    $('li[data-guid="' + data[i].guid + '"]', $ol).text(data[i].new_value);
}

不幸的是,这将遍历每个元素 100 次,使总 DOM 迭代达到 10,000 次。实际上,由于 GUID 是唯一的,它应该遍历第一个元素 100 次,最后一个元素只运行一次,使其运行 5,050 次。

我想我想知道是否有办法将其视为 ID 选择器,当它找到符合条件的元素然后跳出循环时它会停止。

--

squint 的解决方案(如果我的解释是正确的)

var data = [
    {guid: "guid_1", new_value: "I"},
    {guid: "guid_2", new_value: "II"},
    {guid: "guid_3", new_value: "III"},
    {guid: "guid_4", new_value: "IV"}
];

// Hashmap in case array is not the same order as list items, look up by GUID
var hashmap = {};
for (var i = 0, l = data.length; i < l; ++i) {
    hashmap[data[i].guid] = data[i];
}

var $ol = $('#list');
$('li[data-guid]', $ol).text(function () {
    var item = hashmap[$(this).attr('attr-guid')];
    return item ? item.new_value : 'N/A';
});

【问题讨论】:

  • 我想有$(document.querySelector('CSS selector')),但我不确定它是否更高效,尽管它明确设计为只返回第一个匹配项。
  • document.getElementById("list").querySelectorAll('li[data-guid]') 然后迭代结果。
  • @squint:如果您使用的是querySelectorAll(),那么链接方法是否会更快,就像您之前的评论一样,而不是仅仅使用querySelectorAll('#list li[data-guid]')
  • 可能取决于实现,但我相信通常会从右到左选择,这意味着首先会选择所有 li[data-guid],然后每个人都需要验证它是否在 @ 987654333@。如果是这样,那么它会更慢。
  • @MMiller:至于更惯用但性能更好的 jQuery 解决方案:$("#list").find("li[data-guid]").text(function() { return data.new_value; });。如果您只需要第一个 N 元素,则可以将 .slice(0, N) 放在 .text() 之前。

标签: javascript jquery performance css-selectors


【解决方案1】:

在 jQuery 中,您可以使用 :first 选择器仅获取集合的第一个元素,但是,请引用官方 jQuery 文档:

因为 :first 是一个 jQuery 扩展而不是 CSS 规范的一部分,所以使用 :first 的查询无法利用原生 DOM querySelectorAll() 方法提供的性能提升。为了在使用 :first 选择元素时获得最佳性能,首先使用纯 CSS 选择器选择元素,然后使用 .filter(":first")。

:first 选择器和 .filter() 方法并没有真正改善/提升您的代码。

如果你只想选择第一个元素,那么最好的解决方案是使用document.querySelector(),它会在第一个元素上停止并返回它。

原来是这样:

var $ol = $('#list');
for (var i = 0; i < data.length; ++i) {
    $(document.querySelector('li[data-guid="' + data.guid + '"]'), $ol).text(data.new_value);
}

【讨论】:

  • 以这种方式使用:eq() 不会提供任何性能优势。它仍然只是解决问题的错误方法。我敢打赌:first 只是:eq(0) 的糖。
【解决方案2】:

这只运行 data.length 次(见控制台日志)

    <ol id="list">
     <li data-guid="1">Coffee</li>
     <li data-guid="2">Tea</li>
     <li data-guid="5">Milk</li>
     <li data-guid="6">Water</li>
    </ol> 

    var $ol = $('#list');
    var data = [[1,"Saab"], [2,"Volvo"], [3,"BMW"], [6,"Nissan"]]; 
    for (var i = 0; i < data.length; ++i) {
       $ol.find('li[data-guid="' + data[i][0] + '"]').text(data[i][1]);
       console.log(i);
    }

http://jsfiddle.net/rLbd7fuc/

【讨论】:

  • 数组只运行data.length次,但是jQuery遍历列表中的每一项data.length次,导致data.length^2次迭代。
  • 米勒感谢澄清。这个怎么样: $('#list li').each(function(){ for (var i = 0; i jsfiddle.net/rLbd7fuc/1
  • 如果您需要中断有序列表上的迭代,请在每个循环中返回 false。 (api.jquery.com/jquery.each)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
  • 2010-11-01
  • 2016-07-09
  • 2018-07-11
  • 2012-12-27
  • 2011-11-07
相关资源
最近更新 更多