浏览器渲染

146 阅读2分钟

浏览器是多进程架构

Renderer Process

渲染进程包括

  • Compositor Thread
  • Main Thread(主线程),我们基本上都是和它打交道
  • Compositor Tile Workers

anatomy-of-a-frame.svg
The Anatomy of a Frame

Rendering

动画

<!DOCTYPE html>
<html lang="en">
  <head>
    <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>浏览器渲染原理</title>
    <style>
      body {
        position: relative;
      }
      .box {
        width: 100px;
        height: 100px;
        background: #94a3b8;
      }
      .one {
        position: absolute;
        background: #818cf8;
        animation: slide 3s infinite;
      }

      @keyframes slide {
        from {
          top: 0px;
        }
        to {
          top: 500px;
        }
      }
    </style>
  </head>
  <body>
    <div class="box one"></div>
  </body>
</html>

当使用上面的的代码做animation时, 浏览器Performance面板有以下数据
image.png
可以看到每个frame或者每16.7ms, Main Thread都会执行Layout/painting, 在没有大规模计算的情况下动画是能够保持60帧/s.

计算

一旦有某些脚本设计大量计算,这些会造成layout/paint的动画就可能会掉帧,或者卡顿。添加以下代码模拟计算

// 省略...
<button id="btn">计算</button>
<script>
  const btn = document.querySelector("#btn");
  btn.addEventListener("click", () => {
    // 模拟计算
    for (let i = 0; i < 10000; i++) {
      console.log("");
    }
  });
</script>

点击按钮后,动画会卡顿,帧率59下降到55fps
image.png
此时Performance面板的数据是这样子的,3900ms~4400ms, 事件回调执行,回调函数执行计算任务阻塞了rendering,使浏览器没有机会执行渲染任务
image.png

优化

大量计算会阻塞rendering, 我们可以使用requestAnimationFrame/requestIdleCallback将大任务分解成小任务,(raf callback会在rendering之前执行, ric在rendering之后执行), 点击按钮,帧率维持在59fps

<script>
  const btn = document.querySelector("#btn");
  btn.addEventListener("click", () => {
    let i = 0;

    function workLoop() {
      if (i >= 10000) {
        console.log("完成");
        return;
      }
      for (let j = 0; j < 100; j++) {
        i++;
        console.log("");
      }
      requestAnimationFrame(workLoop);
    }

    requestAnimationFrame(workLoop);
  });
</script>

此时的Performance面板, 可以看到大计算任务分解成一个个小的raf里面,每一帧都有机会让浏览器layout/paint, 这样动画更加流畅。利用raf, 我们也可以优化长列表处理, 长列表分成一个个小列表处理。
image.png

高性能动画[3]

这部分单独再复习

尽管raf/ric能够活得流畅的动画效果,但是依然存在问题,每一帧都存在layout/paint, 我们应该尽可能避免在动画过程中发生layout/paint(重排/重绘),
拿上面的例子来说, 我们可以使用CSS transform属性移动元素, 而不是top left等, 使用以下代码比较tranform和top

<!DOCTYPE html>
<html lang="en">
  <head>
    <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>浏览器渲染原理</title>
    <style>
      body {
        position: relative;
      }
      .box {
        width: 100px;
        height: 100px;
        background: #94a3b8;
      }
      .one {
        position: absolute;
        left: 400px;
        background: #818cf8;
        animation: slide-transform 3s infinite;
      }
      .two {
        position: absolute;
        left: 600px;
        background: #fb7185;
        animation: slide-top 3s infinite;
      }
      #btn {
        position: absolute;
        right: 0;
      }

      @keyframes slide-transform {
        from {
          transform: translateY(0px);
        }
        to {
          transform: translateY(500px);
        }
      }
      @keyframes slide-top {
        from {
          top: 0;
        }
        to {
          top: 500px;
        }
      }
    </style>
  </head>
  <body>
    <div class="box one">transform</div>
    <div class="box two">top</div>
    <button id="btn">计算</button>
    <script>
      const btn = document.querySelector("#btn");
      btn.addEventListener("click", () => {
        // 模拟计算
        for (let i = 0; i < 10000; i++) {
          console.log("");
        }
      });
    </script>
  </body>
</html>

当我们按下按钮的时候,右边的红色块(使用top属性做动画), 会有明显的卡顿,而左边的不会
image.png
绿框框说明发生了painting

使用transform

可以看到, animtion中transform移动元素,不会有layout/paint, 因此点击了计算按钮,这个动画依然流畅
image.png
image.png

使用top属性

由于每一帧都要有layout/paint, 当有大量计算任务时, 就会阻塞rendering, 因此造成动画卡顿
image.png
image.png

参考

  1. The Anatomy of a Frame aerotwist.com/blog/the-an…
  2. Inside look at modern web browser (part 3)developer.chrome.com/blog/inside…
  3. How the browser renders a web page? medium.com/jspoint/how…
  4. How to create high-performance CSS animationsweb.dev/animations-…
  5. How the browser renders a web page? — DOM, CSSOM, and Rendering medium.com/jspoint/how…