必须缓存DOM查询结果,因每次调用getElementById或querySelector都会遍历DOM树、开销大;应提前获取并存为变量,避免在循环、高频事件中重复查询导致性能明显下降。

直接把查到的 DOM 元素存进变量里,后续操作都用这个变量,别反复调用 document.getElementById、querySelector 这类方法——这是最简单也最有效的缓存方式。
为什么必须缓存 DOM 查询结果
每次调用查询方法,浏览器都要遍历整个 DOM 树或部分结构,匹配选择器。这个过程不是“读内存”,而是实时查找,开销明显。尤其在循环、事件回调或高频函数中重复查询,性能损耗会快速叠加。更关键的是,某些查询(如访问 offsetWidth)还会强制触发重排(reflow),进一步拖慢脚本执行。
怎么缓存才真正有效
缓存不是随便声明一个变量就行,重点在于作用域和复用时机:
- 在函数外或模块顶层缓存:适用于全局唯一、长期存在的元素(如
#header、.main-nav),避免每次函数调用都重新查 - 在函数内首次使用时缓存:适合局部逻辑中多次使用的元素,用
let el = el || document.querySelector(...)或简单判断即可 - 避免缓存已移除或可能被替换的节点:如果元素可能被
innerHTML清空或被框架替换,缓存值会变成“悬空引用”,后续操作无效甚至报错
常见缓存写法对比
不推荐这样写(重复查询):
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
for (let i = 0; i < 10; i++) {
document.getElementById('list').appendChild(createItem(i));
}
推荐这样写(一次查询,多次使用):
const list = document.getElementById('list');
for (let i = 0; i < 10; i++) {
list.appendChild(createItem(i));
}
更进一步,如果要批量插入大量节点,还应配合 DocumentFragment,把 DOM 操作从 10 次降到 1 次。
顺便注意:尺寸属性也要缓存
像 element.offsetWidth、element.clientHeight 这类属性,每次读取都可能引发同步重排。如果一段逻辑里多次用到某个元素的宽度,应该:
- 只读一次,赋值给变量(例如
const width = el.offsetWidth;) - 后续所有计算都基于该变量,而不是反复读取
- 仅当明确知道布局已更新(比如动画结束、resize 后)才重新读取

















