定义

优先显示与用户操作有关的内容。浏览器接收到 HTML、CSS、JavaScript 字节,到转化成浏览器内的像素点。这一系列的有一个中间过程。性能优化就是了解这一中间过程,即关键渲染路径

image.png

通过优化关键路径渲染,可以显著提高首屏渲染速度。

原理

浏览器如何渲染的👇

  • 字节 → 字符 → 令牌 → 节点 → 对象模型。
  • HTML 标记转换成文档对象模型 (DOM);CSS 标记转换成 CSS 对象模型 (CSSOM)。
  • DOM 和 CSSOM 是独立的数据结构。
  • DOM 树与 CSSOM 树合并后形成渲染树。
  • 渲染树只包含渲染网页所需的节点。
  • 布局计算每个对象的精确位置和大小。
  • 最后一步是绘制,使用最终渲染树将像素渲染到屏幕上。

当浏览器请求某个网址时,会将二进制字节转化成指定编码的字符:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta name="viewport" content="width=device-width,initial-scale=1">
  5. <link href="style.css" rel="stylesheet">
  6. <title>Critical Path</title>
  7. </head>
  8. <body>
  9. <p>Hello <span>web performance</span> students!</p>
  10. <div><img src="awesome-photo.jpg"></div>
  11. </body>
  12. </html>

一、处理 DOM

  1. 转换:原始字节到字符编码
  2. 令牌化:将字符转化成令牌,每个令牌都具有特殊含义和一组规则。例如: <html> <head>
  3. 词法分析:将令牌转化成满足某种属性和规则的节点对象
  4. 构建 DOM 树:构建父子关系,以及树形数据结构

image.png

二、处理 CSSOM

和处理 DOM 的过程类似。

image.png

  1. body { font-size: 16px }
  2. p { font-weight: bold }
  3. span { color: red }
  4. p span { display: none }
  5. img { float: right }

CSS 字节转换成字符,接着转换成令牌和节点,最后链接到一个称为 “CSS 对象模型”(CSSOM) 的树结构内:
image.png

三、处理渲染树

合并 DOM、CSSOM 成为渲染树
image.png

四、布局

计算每个对象的位置和大小,如果设置了 display: none; 则不参与布局。

五、绘制

将最终渲染树打印在浏览器上,就完成了我们平常看到的栩栩如生的页面。

如何优化

关键点

  • CSS 是阻塞渲染的资源。需要将它尽早、尽快地下载到客户端,以便缩短首次渲染的时间
  • 让 JavaScript 异步执行,并去除关键渲染路径中任何不必要的 JavaScript
  • 使用 Lighthouse 审查页面,按照提示做相应的调整
  • 最大限度减小以下三种可变因素
    • 关键资源的数量:删除它们,延迟它们的下载,将它们标记为异步等
    • 关键路径长度:优化关键字节数(比如网页大小)以缩短下载时间
    • 关键字节的数量:优化其余关键资源的加载顺序,尽早下载所有关键资产
  • 消除阻塞渲染的 CSS 和 JavaScript
  • 优化 JavaScript 的使用:默认情况下,JavaScript 资源会阻塞解析器
    • 首选异步加载
    • 避免同步服务器调用,比如使用异步方法 navigator.sendBeacon() 用于埋点数据上报
    • 延迟解析 JavaScript
    • 避免运行时间长的 JavaScript
  • 优化 CSS 的使用:首次构建网页时,JavaScript 常常受阻于 CSS,确保非关键资源标记为异步
    • 将 CSS 置于 head 标签内
    • 避免使用 CSS import
    • 将关键 CSS 直接内联到 HTML 文档内

JavaScript 执行时序👇
image.png

案例

优化前

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta name="viewport" content="width=device-width,initial-scale=1">
  5. <link href="style.css" rel="stylesheet">
  6. </head>
  7. <body>
  8. <p>Hello <span>web performance</span> students!</p>
  9. <div><img src="awesome-photo.jpg"></div>
  10. <script src="app.js"></script>
  11. </body>
  12. </html>

image.png
解释:

  • 关键渲染路径有3个:HTML、CSS、JavaScript 图中蓝色部分
  • 注意 Render processblocking 部分
    • JS 运行发生于 CSSOM 完成后
    • CSS 和 JS 都是阻塞分析器的

优化后

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta name="viewport" content="width=device-width,initial-scale=1">
  5. <link href="style.css" rel="stylesheet" media="print">
  6. </head>
  7. <body>
  8. <p>Hello <span>web performance</span> students!</p>
  9. <div><img src="awesome-photo.jpg"></div>
  10. <script src="app.js" async></script>
  11. </body>
  12. </html>

image.png
解释:

  • 脚本不再阻止解析器,也不再是关键渲染路径的组成部分
  • 由于没有其他关键脚本,CSS 也不需要阻止 domContentLoaded 事件
  • domContentLoaded 事件触发得越早,其他应用逻辑开始执行的时间就越早

Ref