一天一个前端知识点(11):浏览器的重绘(Repaint)和重排(Reflow)

17 阅读2分钟

浏览器的重排和重绘是网页性能优化中的重要概念,它们指的是浏览器对网页进行重新布局和重新绘制的过程。虽然它们常常被一起提到,但它们是不同的概念。

重排(Reflow)指的是当 DOM 元素的布局和几何属性发生改变时,浏览器需要重新计算元素的几何属性,然后重新排列页面布局。这个过程是非常消耗性能的,因为浏览器需要重新计算每个受影响的元素的大小、位置等属性。

重绘(Repaint)指的是当元素的样式发生改变,但是没有改变其布局属性时,浏览器需要重新绘制这个元素。这个过程比重排消耗的性能要少一些,但也是需要避免的。

通常,重排和重绘都是由 JavaScript 操作 DOM 或者改变样式属性引起的。因此,减少 DOM 操作和样式修改可以有效地减少重排和重绘,从而提高网页性能。

以下是一些可以减少重排和重绘的技巧

  • 避免频繁修改 DOM:尽量在一次操作中完成多个修改。
// 不好的示例
for (let i = 0; i < 1000; i++) {
  document.getElementById('list').innerHTML += '<li>' + i + '</li>';
}

// 好的示例
let html = '';
for (let i = 0; i < 1000; i++) {
  html += '<li>' + i + '</li>';
}
document.getElementById('list').innerHTML = html;

  • 使用 CSS3 动画:使用 translate、rotate、scale 等 CSS3 属性来实现动画,避免使用 position 和 left、top 等属性。
// 不好的示例
.box {
  position: absolute;
  top: 0;
  left: 0;
  transition: all .5s;
}
.box:hover {
  top: 100px;
  left: 100px;
}

// 好的示例
.box {
  position: absolute;
  top: 0;
  left: 0;
  transform: translate(0, 0);
  transition: transform .5s;
}
.box:hover {
  transform: translate(100px, 100px);
}
  • 使用虚拟 DOM:虚拟 DOM 可以最小化重排和重绘的次数,提高网页性能。
// 不好的示例
const list = document.getElementById('list');
for (let i = 0; i < data.length; i++) {
  const item = document.createElement('li');
  item.textContent = data[i];
  list.appendChild(item);
}

// 好的示例
const list = new VirtualList(data);
document.body.appendChild(list.render());
  • 尽量避免使用 table 布局:table 布局需要计算大量的单元格,容易导致性能问题。
// 不好的示例
<table>
  <tr>
    <td>1</td>
    <td>2</td>
  </tr>
  <tr>
    <td>3</td>
    <td>4</td>
  </tr>
</table>

// 好的示例
<div class="table">
  <div class="row">
    <div class="cell">1</div>
    <div class="cell">2</div>
  </div>
  <div class="row">
    <div class="cell">3</div>
    <div class="cell">4</div>
  </div>
</div>

  • 使用缓存:尽量避免重复计算,可以使用缓存技术来提高性能。
// 不好的示例
function fibonacci(n) {
  if (n === 0 || n === 1) {
    return n;
  }
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// 好的示例
const cache = {};
function fibonacci(n) {
  if (n === 0 || n === 1) {
    return n;
  }
  if (cache[n]) {
    return cache[n];
  }
  const result = fibonacci(n - 1) + fibonacci(n - 2);
  cache[n] = result;
  return result;
}