透过performance探究js操作dom样式时浏览器会做什么?

浏览器对回流(重排)、重绘的优化策略

“优化队列”

image

如果只是读取“敏感”属性,没有对节点进行几何改变,js执行期间仅会进行样式计算,不会强制布局。

数据缓存

image

改变节点的几何位置,会导致缓存失效

image

测试环境

Chrome 版本 96.0.4664.45(正式版本) (64 位)

测试代码

点击查看代码


  
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  
  
    <div id="div">
      <div></div>
    </div>
    <button>点击测试</button>
    <script>
      const div = document.getElementById('div');
      const btn = document.querySelector('button');

      btn.onclick = () => {
        // do something
      };
    </script>
  


设置节点的style时浏览器的多种处理情况

仅观察代码中btn点击事件附近相关的浏览器处理

浏览器在js执行期间什么都不做

js执行之后进行样式计算、更新分层树、绘制、合成

测试情况

点击事件中没有代码
btn.onclick = () => {
    // do something
};
设置无关元素几何(位置、尺寸等)的属性
btn.onclick = () => {
    div.style.color = 'red';
};
设置无关元素几何(位置、尺寸等)的属性并读取该元素的一些样式属性
btn.onclick = () => {
    div.style.color = 'red';
    const { color, width, height } = div.style;
}

performance记录

image

image

js执行之后进行样式计算、布局、更新分层树、绘制、合成

比上一个多了一个布局步骤

测试情况

设置有关元素几何(位置、尺寸等)的属性
btn.onclick = () => {
    div.style.height = '100px';
}
设置有关元素几何(位置、尺寸等)的属性并读取该元素的非“敏感”样式属性
btn.onclick = () => {
    div.style.height = '100px';
    const { color, width, height } = div.style;
}

performance记录

image
image

浏览器在js执行期间进行样式计算

样式计算后,如果有新的样式设置,会将其放到“渲染优化队列”中

读取“敏感”属性

btn.onclick = () => {
    const top = div.scrollTop,
      width = div.clientWidth;
};

performance记录

image

读取“敏感”属性后并设置无关节点几何位置的样式

btn.onclick = () => {
    const top = div.scrollTop;
    div.style.color = 'red';
    div.style.backgroundColor = 'blue';
};

performance记录

image

读取“敏感”属性后并设置有关节点几何位置的样式

btn.onclick = () => {
    const top = div.scrollTop;
    div.style.color = 'red';
    div.style.height = '100px';
};

performance记录

image

读取“敏感”属性后并设置无关节点几何位置的样式,之后再次读取“敏感”属性

浏览器会执行两次样式计算

btn.onclick = () => {
    const clientHeight = div.clientHeight;
    div.style.color = 'red';
    const clientWidth = div.clientWidth;
};

performane记录

image

读取“敏感”属性后并设置有关节点几何位置的样式,之后再次读取“敏感”属性

浏览器会在js执行期间进行两次样式计算并强制同步布局。

btn.onclick = () => {
    const clientHeight = div.clientHeight;
    div.style.height = '100px';
    const clientWidth = div.clientWidth;
};

performane记录

image

与节点的class相关的浏览器处理操作

浏览器在js执行期间什么也不做。所以这就是网上说的使用class样式减少对节点style的操作?

.style {
    color: red;
    height: 100px;
}
btn.onclick = () => {
    const className = div.className;
    div.className = `style`;
    // 或者下面的代码
    /*
    div.classList.add('style');
    const className = div.classList.toString();
    */
};

performance记录

image

关于window.getComputedStyle()

image

优化回流、重绘

  1. 网上说的推荐使用class类名/cssText设置样式少用style操作dom可以减少浏览器的一些操作(样式计算、强制同步布局等),减少性能消耗
  2. 网上说的操作style时,读写分离,先读后写,也可以减少一些样式计算的性能消耗
  3. "离线"修改dom
    • 使用documentFragment
    • 克隆需要操作的节点,操作dom完成后,再替换被克隆的节点
    • 使用display: none隐藏节点,操作dom完成后,再显示节点。最多有两次回流,避免了可能的更多的回流。
  4. 使用变量缓存“敏感”属性(除了getComputedStyle,currentStyle),offsetWidth等的值是数字,没有引用关系,可以被当作一个新值使用
  5. 使用绝对定位,减少其对其他节点的影响
  6. 没事儿不要用window.getComputedStyle()获取样式

来源

https://www.phpied.com/rendering-repaint-reflowrelayout-restyle/
https://dl.acm.org/doi/10.1145/1772690.1772741
https://yonatankra.com/layout-reflow/
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/getComputedStyle

posted @ 2021-12-04 09:27  酉云良  阅读(98)  评论(0)    收藏  举报