【问题标题】:Optimizing jQuery selector / addBack() when dealing with a large collection处理大型集合时优化 jQuery 选择器/addBack()
【发布时间】:2025-12-03 19:15:01
【问题描述】:

我使用 jQuery 有意从一个可能很大的 html 表中的元素中删除 css 类。请参阅下文了解我为什么这样做。

目前我正在这样做:

var tableElements = $("#TreeListElemente").find("*").addBack();
tableElements.removeClass("dxtl dxtl__B2 dxtl__B0 dxtlSelectionCell dxtlHeader dxtl__B3 dxtlControl dx-wrap dxtl__IM dxeHyperlink");

表格有时很大并且有很多元素。我想加快页面加载/DOM 操作。

IE 的内置 Javascript 分析器告诉我,尤其是 .addBack() 很慢。它似乎做了某种排序,这对我的用例来说完全没有必要。我能摆脱它吗?除了 addBack() 之外,还有其他方法可以包含所选元素本身吗?

IE javascript 分析器:大约 60000 个元素的集合的执行时间。包含时间在第三列

或者是否有另一种更有效的方法来从大量元素中删除类,即选择一个元素、它本身和所有子元素?

注意:我为什么要这样做:我使用的是 DevXpress TreeList 组件,它带有自己的样式。没有简单的方法可以在服务器端“取消样式”,因此我选择在客户端执行上面演示的方式。最后,我选择 TreeList,所有子元素,并从中删除相关的 css 类。

更新/解决方案 1

我已经成功实施了 Frédéric Hamidi 提出的解决方案,并取得了相当大的进步:

IE javascript profiler:大约 60000 个元素的集合的执行时间,使用 Frederic 的提议。包含时间在第三列

addBack() 操作所需的时间已经过去了,剩下的只是其他的东西。这意味着总体上提高了 4 倍以上。耶!

更新/解决方案 2

我也实现了 A. Wolff 提出的解决方案,并得到了一些额外的改进:

IE javascript profiler:大约 60000 个元素的集合的执行时间,使用 A. Wolff 的提议。包含时间在第三列

find() 操作所需的时间已经过去,只剩下其他的东西了。这意味着在我的机器上稍微改进了大约 10 毫秒。酷!

这是我现在使用的解决方案:

$("#TreeListElemente, #TreeListElemente [class]").removeClass("dxtl dxtl__B2 dxtl__B0 dxtlSelectionCell dxtlHeader dxtl__B3 dxtlControl dx-wrap dxtl__IM dxeHyperlink");

【问题讨论】:

  • $("#TreeListElemente, #TreeListElemente [class]").removeClass("...");???
  • 顺便说一句,不能只删除/更新相关的样式表吗?
  • @A.Wolff,不,很遗憾没有,请参阅我在问题中的说明。
  • 编辑后,您是否对其进行了测试:$("#TreeListElemente, #TreeListElemente [class]").removeClass("dxtl dxtl__B2 dxtl__B0 dxtlSelectionCell dxtlHeader dxtl__B3 dxtlControl dx-wrap dxtl__IM dxeHyperlink");?我想它会更高效
  • @A.Wolff 我现在也对其进行了测试。它快一点,大致省略了显式查找操作所花费的时间,但总体上并没有快多少。但是,代码更具可读性。请作为答案发布,并简要说明它比原始解决方案或 Frederic 的更好,我会接受它作为答案。

标签: javascript jquery css performance


【解决方案1】:

addBack() 确实执行排序以将匹配的元素按文档顺序排列。简单的替代方案add() 的作用完全相同,因此无法解决您的问题。

但是,文档足以提供解决方案:

创建一个 jQuery 对象,其中的元素具有明确定义的顺序和 在没有排序开销的情况下,使用$(array_of_DOM_elements) 签名。

因此,为了避免这种开销,您可以编写:

var ancestor = $("#TreeListElemente"),
    tableElements = $(ancestor.find("*").get().concat(ancestor[0]));

get()concat() 最终会在底层构建两个数组,因此会影响性能。最终结果可能比您当前的方法更快,具体取决于您匹配的元素数量。

【讨论】:

  • 非常好。这带来了巨大的改进,请参阅问题中的更新 1。
【解决方案2】:

选择 ID 为 TreeListElemente 的元素及其所有后代的相关选择器将是:

"#TreeListElemente, #TreeListElemente *"

现在您可以过滤掉具有类的后代:

"#TreeListElemente, #TreeListElemente [class]"

所以它会给出:

$("#TreeListElemente, #TreeListElemente [class]").removeClass("dxtl dxtl__B2 dxtl__B0 dxtlSelectionCell dxtlHeader dxtl__B3 dxtlControl dx-wrap dxtl__IM dxeHyperlink");

【讨论】:

  • 谢谢!我目前使用此解决方案,请参阅问题中的更新 2。在我的情况下,它比@Frédéric Hamidi 的解决方案略快,并且更易于阅读。
【解决方案3】:

这是一个想法:

function deClassify(jq, classes) {
  var remove = classes.join(' ');
  jq.find('.' + classes.join(',.')).removeClass(remove);
  jq.removeClass(remove);
}

deClassify($('.keepme'), ['remove', 'remove2', 'remove3']);
.remove, .remove2, .remove3 {
  color: red;
}
.keepme, .keepme2 {
  font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="keepme remove remove2">
  <div class="keepme2 remove remove3">x</div>
</div>

这样可以避免“选择”不匹配的元素,减少负载,当然也不涉及额外的排序……

【讨论】: