当DOM树中的元素发生改变时,浏览器需要重新计算元素的位置和大小,这个过程称为reflow;当元素的外观改变,但不影响布局时,浏览器只需要重新绘制元素,这个过程称为repaint。
JS网页repaint与reflow 的区别及优化方式
repaint和reflow的概念
当DOM树中的元素发生改变时,浏览器需要重新计算元素的位置和大小,这个过程称为reflow;当元素的外观改变,但不影响布局时,浏览器只需要重新绘制元素,这个过程称为repaint。
repaint和reflow的区别
reflow是一项非常昂贵的操作,因为浏览器需要重新计算和布局所有的元素。而repaint的代价相对较小,因为浏览器只需要重新绘制某个元素或者部分元素就可以了。
repaint和reflow的优化方式
减少对DOM的操作
reflow的发生和DOM的改变直接相关。减少对DOM的操作可以避免reflow的发生。因此,在使用JavaScript动态操作DOM时,应该尽可能地减少对DOM节点的操作,可以考虑使用字符串拼接、documentFragment等方式来批量插入DOM。
减少访问样式信息
在进行DOM操作的时候,浏览器需要获取样式信息进行重排。因此频繁访问样式信息,会导致reflow的发生。为了减少reflow的发生,可以将需要访问的样式信息提前存储到变量中,然后一次性读取。
// bad
for (let i = 0; i < 1000; i++) {
document.querySelector("#app").style.left = i + "px";
document.querySelector("#app").style.top = i + "px";
}
// good
const app = document.querySelector("#app");
for (let i = 0; i < 1000; i++) {
app.style.left = i + "px";
app.style.top = i + "px";
}
减少无用的重排和重绘
一些无用的DOM操作会导致reflow和repaint的发生,这些操作可能不会改变DOM树结构和样式信息。因此,需要尽可能减少无用的操作。
// bad
for (let i = 0; i < 1000; i++) {
document.querySelector("#app").style.left = i + "px";
document.querySelector("#app").style.top = i + "px";
}
// good
const app = document.querySelector("#app");
const leftValue = app.style.left;
const topValue = app.style.top;
for (let i = 0; i < 1000; i++) {
app.style.left = parseInt(leftValue) + i + "px";
app.style.top = parseInt(topValue) + i + "px";
}
示例说明
示例一
<div id="container">
<div class="item">
<img src="" alt="image">
<h3>Title</h3>
<p>Content</p>
</div>
<div class="item">
<img src="" alt="image">
<h3>Title</h3>
<p>Content</p>
</div>
<div class="item">
<img src="" alt="image">
<h3>Title</h3>
<p>Content</p>
</div>
...
</div>
上述代码中,我们需要动态地向容器中添加元素。如果我们使用以下的方式进行操作:
const container = document.querySelector("#container");
for (let i = 0; i < 100; i++) {
const item = document.createElement("div");
item.classList.add("item");
const img = document.createElement("img");
img.src = "https://...";
const h3 = document.createElement("h3");
h3.textContent = "Title";
const p = document.createElement("p");
p.textContent = "Content";
item.appendChild(img);
item.appendChild(h3);
item.appendChild(p);
container.appendChild(item);
}
每次添加一个元素会触发一次reflow,增加计算开销。而我们可以使用以下的方式进行操作:
const container = document.querySelector("#container");
const items = [];
for (let i = 0; i < 100; i++) {
const item = document.createElement("div");
item.classList.add("item");
const img = document.createElement("img");
img.src = "https://...";
const h3 = document.createElement("h3");
h3.textContent = "Title";
const p = document.createElement("p");
p.textContent = "Content";
item.appendChild(img);
item.appendChild(h3);
item.appendChild(p);
items.push(item);
}
items.forEach(item => {
container.appendChild(item);
});
这样可以将100次reflow减少到1次。
示例二
<div id="container">
<div class="item">
<img src="" alt="image">
<h3>Title</h3>
<p>Content</p>
</div>
<div class="item">
<img src="" alt="image">
<h3>Title</h3>
<p>Content</p>
</div>
<div class="item">
<img src="" alt="image">
<h3>Title</h3>
<p>Content</p>
</div>
...
</div>
我们需要实现一个动画,将所有.item元素横向移动。以下是一个可能的实现方式:
const items = document.querySelectorAll(".item");
let leftValue = 0;
setInterval(() => {
items.forEach(item => {
item.style.left = leftValue + "px";
});
leftValue++;
}, 16);
在上述代码实现过程中,每次设置left值都会触发reflow,增加计算开销。而我们可以将left值提前存储,批量修改元素位置。以下是优化后的代码:
const items = document.querySelectorAll(".item");
const styleLefts = [];
for (let i = 0; i < items.length; i++) {
styleLefts[i] = items[i].style.left;
}
let leftValue = 0;
setInterval(() => {
styleLefts.forEach((left, index) => {
items[index].style.left = parseInt(left) + leftValue + "px";
});
leftValue++;
}, 16);
这样可以将100次reflow减少到1次。
本文标题为:JS网页repaint与reflow 的区别及优化方式
基础教程推荐
- 完美解决ajax访问遇到Session失效的问题 2023-01-20
- 详解CSS玩转图片Base64编码 2022-11-20
- 浅谈由position属性引申的css进阶讨论 2022-11-20
- 仿豆瓣分页原型(Javascript版) 2023-12-02
- Ajax提交Form表单页面仍会刷新问题的快速解决办法 2023-01-26
- 详解CSS不定宽溢出文本适配滚动 2022-11-13
- 详解addEventListener的三个参数之useCapture 2024-01-06
- 借助得力工具五分钟快速制作CSS导航菜单 2024-01-19
- SSM+layui前端form表单传到后端乱码问题解决 2022-11-22
- 如何在CSS中绘制曲线图形及展示动画 2022-11-13