回流与重绘

发布日期:2017-09-07 阅读量:385

1. 回流

   当我们对DOM的修改引发了DOM几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),然后再将计算的结果绘制出来,这个过程叫做回流(重排)。

2. 重绘

   当我们对DOM的修改导致了样式的变化、却并未影响其几何属性(比如只修改了颜色或背景色)时,浏览器不需要重新计算元素的几何属性,直接为该元素绘制新的样式(跳过了回流环节),这个过程叫做重绘。因此,重绘不一定导致回流,回流一定会导致重绘。

3. 触发举例

   1)改变DOM元素的几何属性(width、height、padding、margin、left、right 等)。当一个DOM元素的几何属性发生变化时,所有和它相关的节点(比如父子节点、兄弟节点等)的几何属性都需要进行重新计算,它会带来巨大的计算量;

   2)改变DOM树的结构:节点的增删、移动等操作;

   3)获取一些特定的属性的值:offsetTop、offsetLeft、offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight。这些值有一个共性,就是需要通过即时计算得到,因此浏览器为了获取这些值,也会进行回流。

4、优化触发举例

   1)多次计算得到一个元素的布局。

    const el = document.getElementById('el'); //获取元素
    for(let i = 0; i < 10; i ++) {
        // 每次循环都要获取多次导致回流的值
        el.style.top = el.offsetTop + 10 + 'px';
        el.style.left = el.offsetLeft + 10 + 'px';
    }

   优化:

    const el = document.getElementById('el'); //获取元素
    let oT = el.offsetTop;
    let oL = el.offsetLeft;
    for(let i = 0; i < 10; i ++) {
        oT += 10;
        oL += 10;
    }
    el.style.top = oT + 'px';
    el.style.left = oL + 'px';

   2)尽量避免样式逐条改变:

    const container = document.getElementById('container');
    container.style.width = '100px';
    container.style.heigt = '100px';
    container.style.border = '1px solid red';
    container.style.color = 'blue';

   优化:

    .change-style {
        width: 100px;
        height: 100px;
        border: 1px solid red;
        color: blue;
    }
    const container = document.getElementById('container');
    container.classList.add('change-style');

   3)DOM离线化:当进行很少的DOM操作时优越性不太明显,但是当操作频繁这样就会非常值得

    const container = document.getElementById('container');
    container.style.width = '100px';
    container.style.heigt = '100px';

   优化:

    const container = document.getElementById('container');
    container.style.display = 'none';
    container.style.width = '100px';
    container.style.heigt = '100px';
    container.style.display = 'block';

   4)浏览器缓存队列: flush 队列。这种机制不是每个浏览器都有。

   浏览器的flush队列会把我们要触发的回流与重绘任务都塞进去,待到队列任务多起来、或者达到一定的时间间隔、或者需要执行的时候,再将这些任务一次性出队,因此这时候我们的回流与重绘只会触发一次。