应优先使用 document.getElementById() 而非 querySelectorAll(),因其为 O(1) 哈希查找,而后者在低配设备上因 CSS 解析开销大而更慢;目标元素有稳定 id 时须缓存,避免循环内重复调用。

硬件瓶颈不是“换工具就能解决”的问题,而是要先判断卡在哪一层——CPU、内存、GPU 还是磁盘 I/O。选错 HTML 数据提取函数,反而会放大瓶颈。
用 document.getElementById() 而不是 querySelectorAll() 的真实原因
在 CPU 主频低于 1.5 GHz 或核心数 ≤ 2 的设备(如二手笔记本、入门级 Chromebook)上,querySelectorAll() 的 CSS 解析开销可能比 DOM 遍历还高。它要构建选择器语法树、匹配伪类、处理复杂属性组合;而 document.getElementById() 是原生哈希查找,平均时间复杂度 O(1)。
- 若目标元素有稳定
id,优先缓存:const tableEl = document.getElementById('data-table'); - 避免在循环里反复调用:不要写
for (let i = 0; i - 当必须用类名定位时,用
getElementsByClassName()(返回 live collection,但比querySelector快)而非querySelector(),尤其在旧版 Edge 或 Safari 14 以下
内存不足时禁用 innerHTML,改用 textContent 和 createDocumentFragment()
频繁设置 innerHTML 会触发完整 HTML 解析 + DOM 构建 + 样式计算 + 布局,对内存小于 2 GB 的设备极易引发 GC 暂停和主线程冻结。实测在 1.5 GB 内存的 Android 设备上,连续 50 次 innerHTML = '...' 可导致页面卡顿超 800ms。
- 纯文本更新一律用
textContent:它跳过 HTML 解析,只更新文本节点内容 - 批量插入 DOM 元素时,先用
document.createDocumentFragment()构建离线树,再一次性appendChild()到真实 DOM - 避免用
insertAdjacentHTML('beforeend', htmlStr)替代textContent—— 它仍走 HTML 解析路径
GPU 不可用时别碰 will-change 和 translateZ(0)
在无独立显卡、或集成显卡驱动未启用硬件加速的设备(如部分 Intel HD Graphics 4000/5000 笔记本),强制开启合成层会让浏览器回退到 CPU 渲染,反而增加主线程负担。Chrome DevTools 的 Rendering 面板中若看到 “Painting” 占比突增,大概率是这个原因。
立即学习“前端免费学习笔记(深入)”;
- 检测是否支持:用
CSS.supports('will-change', 'transform')或CSS.supports('transform', 'translateZ(0)')判断后再注入样式 - 不要全局加
will-change: transform到表格容器——它会让整个表格区域被提升为合成层,吃掉额外内存 - 对仅需滚动优化的长列表,用
contain: layout paint替代will-change,兼容性更好且开销更低
真正容易被忽略的是:很多“卡顿”根本不是提取逻辑的问题,而是你把 fetch() 回来的 HTML 字符串直接塞进 innerHTML,结果浏览器一边解析 HTML,一边还要执行内联脚本、加载图片、触发样式重算——这三件事在低端设备上是串行阻塞的。拆开做,才能让硬件各司其职。



















