说一下分离读写
分离读写,在前端和浏览器渲染上下文中通常指 将 DOM 读取操作和写入操作分开执行,目的是 减少回流(Reflow)和重绘(Repaint),提升性能。
1. 读与写的区别
-
读操作(Read / Measure)
- 获取元素信息,不改变 DOM
常见方法:
element.offsetHeight
element.offsetWidth
element.scrollTop
element.getBoundingClientRect()
window.getComputedStyle(element)
-
写操作(Write / Mutate)
- 修改 DOM 或样式,可能触发回流
常见方法:
element.style.width = '100px'
element.classList.add('active')
element.appendChild(newNode)
2. 为什么要分离读写
-
浏览器渲染机制:
-
DOM 或样式变化 → 标记为脏(需要回流)
-
下一次读尺寸或绘制时,如果发现 DOM 脏了 → 强制回流(Reflow)
-
问题示例:
const height = element.offsetHeight; // 读
element.style.width = '200px'; // 写
const newHeight = element.offsetHeight; // 再读 → 浏览器会强制回流
上面这种“读-写-读”顺序会导致 回流两次,性能开销大
-
优化策略:
-
先全部读,再全部写,避免多次回流
-
即把读写操作分组,减少渲染触发次数
-
3. 实际操作方法
方法 1:批量读写
// 先读取
const height = element1.offsetHeight;
const width = element2.offsetWidth;// 再修改
element1.style.height = height + 'px';
element2.style.width = width + 'px';
方法 2:使用 requestAnimationFrame
// 所有 DOM 读操作在 raf 外层
const readValues = () => {return {height: element.offsetHeight,width: element.offsetWidth};
};requestAnimationFrame(() => {const {height, width} = readValues();element.style.height = height + 'px';element.style.width = width + 'px';
});
好处:让 DOM 修改在下一帧统一执行,减少强制回流
方法 3:使用 Batch / DOM 打包库
-
比如 FastDom 或 前端框架虚拟 DOM
-
自动分离读写操作,批量执行,性能更优
总结
概念 | 说明 |
---|---|
读操作 | 获取 DOM 信息,不修改,可能触发回流 |
写操作 | 修改 DOM 或样式,会触发回流和重绘 |
分离读写 | 先全部读,再全部写,减少回流次数,提高性能 |
优化手段 | 批量读写、requestAnimationFrame、虚拟 DOM、FastDom |
核心理解:
-
浏览器在读写 DOM 时会触发回流/重绘,频繁交替“读-写-读”会导致性能下降
-
分离读写 = 批量读 + 批量写,让浏览器渲染更高效