You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于e.matches()是否遍历DOM及DOM查询性能优化的问询

Element.matches()是否需要遍历DOM来评估选择器?

问题场景

我提出这个疑问是因为遇到了这样的代码场景:

if ( e.matches('.class_1, .class_1 *') ) {
  /* 执行操作 */
} else if ( e.matches('.class_2, .class_2 *') ) {
  /* 执行操作 */
} else if ( e.matches('.class_3, .class_3 *') ) {
  /* 执行操作 */
} else {
  /* 执行操作 */
}

如果e.matches()需要从元素e向上遍历DOM祖先树来判断结果,当前面的条件不成立时,每个else if都会重复这个遍历过程,这看起来不够高效。

优化思路的困惑

于是我考虑改用e.classList.contains()只遍历一次祖先树,确定e向上遍历时最先匹配class_1、class_2、class_3中的哪一个,或者遇到需要停止搜索的祖先元素就终止。但不确定这种方式是否真的更高效:

let currentEl = e;
while ( currentEl ) {
  const classList = currentEl.classList;
  if ( classList.contains('class_1') ) {
    /* 执行操作 */
    break;
  } else if ( classList.contains('class_2') ) {
    /* 执行操作 */
    break;
  } else if ( classList.contains('class_3') ) {
    /* 执行操作 */
    break;
  }
  currentEl = currentEl.parentNode;
} 

补充说明:在我的DOM结构中,class_1的层级始终比class_2深,class_2始终比class_3深。我只需要确定e属于哪一层级,不需要找到具体的元素,只需判断向上遍历时最先匹配的类(如果存在的话)。

后续测试结果与新疑惑(2023年12月24日)

数月后我做了个小测试,结果出乎意料:

  • 当存在匹配元素时,e.closest()和e.matches()速度相近且都很快;
  • 当无匹配元素时,e.closest()会慢很多,但e.matches()速度保持不变。

测试在Firefox中运行,Brave浏览器中5000次迭代会崩溃,但少次迭代的结果类似。

让我疑惑的点:

  1. 如果e.closest()需要向上遍历DOM寻找匹配项,那找到最外层的evt_1和确定不存在evt_2的耗时为什么会有差异?两者理论上都需要遍历5000层级。
  2. 存在匹配时,找到从内向外第2500层的evt_3和第5000层的evt_1的查询耗时没有差异。

测试代码及结果

var
  D = document.createElement("DIV"),
  d = D;
D.className = "evt_1";
for ( let i = 0; i < 5000; i++ ) {
  d = d.appendChild(document.createElement("DIV"));
  if ( i === 2500 ) d.className = "evt_3";
}  

document.body.append(D);
let t = Date.now();
console.log( d.matches(".evt_1, .evt_1 *") + " " + (Date.now() - t) );
t = Date.now();
console.log( d.closest(".evt_1, .evt_1 *") + " " + (Date.now() - t) );
t = Date.now();
console.log( d.closest(".evt_1") + " " + (Date.now() - t) );

t = Date.now();
console.log( d.matches(".evt_2, .evt_2 *") + " " + (Date.now() - t) );
t = Date.now();
console.log( d.closest(".evt_2, .evt_2 *") + " " + (Date.now() - t) );
t = Date.now();
console.log( d.closest(".evt_2") + " " + (Date.now() - t) );

t = Date.now();
console.log( d.matches(".evt_3, .evt_3 *") + " " + (Date.now() - t) );
t = Date.now();
console.log( d.closest(".evt_3, .evt_3 *") + " " + (Date.now() - t) );
t = Date.now();
console.log( d.closest(".evt_3") + " " + (Date.now() - t) );

测试输出:

true 0
[object HTMLDivElement] 0
false 0
null 112
true 0
[object HTMLDivElement] 0

内容的提问来源于stack exchange,提问作者Gary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 09:07:53