【性能优化知识整理】关键路径和优化方式
Google LightHoust 性能优化相关文档 性能优化 (opens new window)
# 关键路径
# 渐进式渲染
一个网页的渲染,通常需要先加载很多资源。如果等所有资源都加载完再进行渲染,会导致页面有很长一段的白屏时间;而如果只加载了一些HTML就尽快让页面渲染,页面看起来就会不完整,对用户体验也不好。因此,浏览器会采取渐进式的渲染,加载最低限度的资源,以免呈现明显中断的体验。
这些资源也就是关键渲染路径中需要的资源(样式、脚本等)
# 关键渲染路径
也可以说是浏览器的渲染过程,也就是面试中常问的“当在地址栏输入一个url后,会发生什么”其中浏览器渲染的部分😦
# 关键路径
浏览器渲染步骤:
- 通过 HTML 构建文档对象模型 (DOM)。
- 通过 CSS 构建 CSS 对象模型 (CSSOM)。
- 应用任何会更改 DOM 或 CSSOM 的 JavaScript。
- 通过 DOM 和 CSSOM 构建渲染树。
- 在页面上执行样式和布局操作,看看哪些元素适合显示。
- 在内存中绘制元素的像素。
- 如果有任何像素重叠,则合成像素。
- 以物理方式将所有生成的像素绘制到屏幕上。
总结来说就是加载HTML文件渲染出DOM树、加载CSS文件渲染出CSSOM树,遇到脚本就解析脚本,完毕后结合生成渲染树,最后计算布局和绘制(回流、重绘)。
# 关键路径上的资源
要等待下载的资源:
- 部分的HTML
- head标签中的CSS
- head标签中的JavaScript
不用等待下载的资源:
- 所有 HTML
- 字体
- Images
- head元素外(例如,位于 HTML 末尾的 script 元素)之外的非阻塞渲染的 JavaScript
- head元素外或media 属性值不适用于当前视口的 CSS,不会阻止内容渲染(可以用这种方法推迟css加载)
也就是解析HTML的过程中,遇到这些资源后不用等待下载完, 异步下载
# 阻塞渲染的资源
文档里面好像只提到了CSS?🤨
浏览器遇到这些资源后,要暂停网页渲染,等资源处理完后再继续渲染,比如默认的CSS。
当浏览器看到 CSS(无论是 style 元素中的内嵌 CSS,还是由 link rel=stylesheet href="..." 元素指定的外部引用的资源)时,浏览器在完成对该 CSS 的下载和处理之前,将避免呈现更多内容。
尽管 CSS 默认会阻塞渲染,但也可以通过更改 <link> 元素的 media 属性来指定与当前条件不匹配的值,将其转换为不阻塞渲染的资源:<link rel=stylesheet href="..." media=print>。 过去已使用此方法,以允许非关键 CSS 以不阻塞渲染的方式加载。
HTML在解析过程中遇到这类资源后,只会阻塞后面的渲染,所以head标签中的阻塞资源需要重点关注,他会阻止整个页面的渲染。
但是这些资源只会阻塞渲染过程,并不会阻塞HTML的解析。
# 阻塞解析的资源
就是常见的那些啦,没有添加defer或async的script,所以不要在head里面添加script标签,要在body的尾部,这样才不会阻塞HTML解析。
因为 JavaScript 可能会在执行时更改 DOM 或 CSSOM。因此,在了解所请求 JavaScript 对网页 HTML 造成的全部影响之前,浏览器就不可能继续处理其他资源。因此,同步 JavaScript 会阻止解析器。
# 优化资源加载
先解释下为什么CSS会阻塞渲染
很简单,如果CSS不阻塞渲染,页面先出现HTML,然后样式再加载完,此时页面的布局等样式就会发生变化,叫非样式内容闪烁(FOUC),这对用户体验不好。
# 预加载扫描器
浏览器的一种优化方式,辅助HTML解析器先扫描原始HTML响应,找出可能要下载的资源,然后主HTML解析器才会发现资源。这样做的好处是即使CSS 和 JavaScript 等资源时阻止了 HTML 解析器,预加载扫描程序也会允许浏览器开始下载 元素中指定的资源。
但是以下资源无法被预加载扫描器发现:
- 由 CSS 使用 background-image 属性加载的图片。这些图片引用位于 CSS 中,预加载扫描器无法发现这些引用。
- 动态加载的脚本,采用 <script> 元素标记(使用 JavaScript 注入 DOM)或使用动态 import() 加载的模块。
- 使用 JavaScript 在客户端上呈现的 HTML。此类标记包含在 - JavaScript 资源的字符串中,预加载扫描器无法发现此类标记。
- CSS @import 声明。
尽量不适用这些,但是如果必须要用,可以给标签设置preload属性
# CSS优化方式
CSS会阻塞页面渲染,常见的优化点有:
- 减少CSS文件大小(老生常谈了)
- 移除未使用CSS(八股文背烂了😦)
- 避免使用@import(这个也是🤨)
- 内联关键CSS(但是从项目维护角度来说,并不太好吧。还有的缺点是写在html里面的基本无法缓存,谨慎使用)
其实也没啥好办法😁看自己CSS水平
# JS优化方式
JS会阻塞页面的解析,常见优化点:
- 给非必要脚本资源添的script标签添加async或defer属性(后面再细谈)
- 不要在JS里面渲染可能是LCP的元素(后面谈)
- 减少JS文件大小(老生常谈了)
后面再补各个优化指标以及工作实际中用到的一些优化技巧