浏览器从获取 HTML到最终在屏幕上显示内容需要完成以下步骤:
- 处理 HTML 标记并构建 DOM 树。
- 处理 CSS 标记并构建 CSSOM 树。
- 将 DOM 与 CSSOM 合并成一个 render tree。
- 根据渲染树来布局,以计算每个节点的几何信息。
- 将各个节点绘制到屏幕上。
经过以上整个流程我们才能看见屏幕上出现渲染的内容,优化关键渲染路径就是指最大限度缩短执行上述第 1 步至第 5步耗费的总时间,让用户最快的看到首次渲染的内容
CSSOM 的构建会阻塞 HTML 的渲染,也会阻塞 JS 的执行,JS 的下载与执行(内联及外部样式表)也会阻塞 HTML 的渲染
# 优化方法
为尽快完成首次渲染,我们需要最大限度减小以下三种可变因素
- 关键资源的数量:可能阻止网页首次渲染的资源
- 关键路径长度:获取所有关键资源所需的往返次数或总时间。
- 关键字节的数量:实现网页首次渲染所需的总字节数,它是所有关键资源传送文件大小的总和。我们包含单个 HTML 页面的第一个示例包含一项关键资源(HTML 文档);关键路径长度也与 1 次网络往返相等(假设文件较小),而总关键字节数正好是 HTML 文档本身的传送大小
优化关键渲染路径的常规步骤如下
- 对关键路径进行分析和特性描述:资源数、字节数、长度
- 最大限度减少关键资源的数量:删除它们,延迟它们的下载,将它们标记为异步等
- 优化关键字节数以缩短下载时间(往返次数)
- 优化其余关键资源的加载顺序:您需要尽早下载所有关键资产,以缩短关键路径长度
关键 CSS
样式表会阻塞渲染,在加载完毕之前是不会显示的,为了让用户以最快的速度看到页面上的内容,可以将页面的某一部分的样式抽离出来,单独放在一个样式表中或者内联在页面中,这样的样式称为关键样式,这部分样式会优先它可以是页面的骨架屏或者是用户刚加载进页面时看到的首屏的内容。
<!doctype html>
<head>
<style> /* inlined critical CSS */ </style>
<script> loadCSS('non-critical.css'); </script>
</head>
<body>
...body goes here
</body>
</html>
@前端进阶之旅: 代码已经复制到剪贴板
预加载 —— preload & prefetch
使用 preload meta 来提升资源加载的优先级
preload会提升资源的优先级因为它标明这个资源是本页肯定会用到 —— 本页优先prefetch会降低这个资源的优先级因为它标明这个资源是下一页可能用到的 —— 为下一页提前加载preload最大的作用就是将下载与执行分离,并且将下载的优先级提到了一个很高的地步,再由我们去控制资源执行的位置
加速样式表下载
样式表是阻塞页面呈现的(注意是呈现,不是解析),正常通过
link加载的外部样式表要等下载,构建CSSOM树才会让页面呈现完成,但是preload能够让样式表的下载和呈现分离
试想,当你在页面的 head 中写了如下的两个样式表
<link href="critial.css" rel="stylesheet" />
<link href="non-critial.css" rel="stylesheet" />
@前端进阶之旅: 代码已经复制到剪贴板
- 第一个是关键
CSS,第二个不是关键 CSS,当页面解析了这两个link标签后开始下载,但是即使critical.css下载解析完毕也不会呈现页面,因为页面还要下载和解析non-critical.css。 - 这时候,就要将
non-critial.css作为预加载,当样式表作为被preload后,他就不会再阻塞页面的呈现,也就是所谓的异步下载,修改后的代码如下:
<link href="critial.css" rel="stylesheet" />
<link rel="preload" href="non-critial.css" as="style" />
<link href="non-critial.css" rel="stylesheet" />