amandakelake / blog

think more!learn more!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

优化关键渲染路径,加速浏览器首次渲染

amandakelake opened this issue · comments

commented

优化关键渲染路径能够让浏览器尽可能快地绘制网页:更快的网页渲染速度可以提高吸引力、增加网页浏览量以及提高转化率。为了最大程度减少访客看到空白屏幕的时间,我们需要优化加载的资源及其加载顺序。
分析关键渲染路径性能  |  Web  |  Google Developers

渲染树构建、布局及绘制

89588ef5-d787-4f20-b9e1-6b9c23c7a6c6

  1. 处理 HTML 标记并构建 DOM 树,初始的 HTML 被完全加载和解析后会触发 DOMContentLoaded 事件
  2. 处理 CSS 标记并构建 CSSOM 树。
  3. 将 DOM 与 CSSOM 合并成一个渲染树renderTree。
  4. 根据渲染树来布局,以计算每个节点的几何信息。
  5. 将各个节点绘制到屏幕上。

优化关键渲染路径_就是指最大限度缩短执行上述第 1 步至第 5 步耗费的总时间。 这样一来,就能尽快将内容渲染到屏幕上,此外还能缩短首次渲染后屏幕刷新的时间,即为交互式内容实现更高的刷新率。

阻塞渲染的CSS

在渲染树构建中,HTML 和 CSS 都是阻塞渲染的资源,HTML 显然是必需的,因为如果没有 DOM,我们就没有可渲染的内容,但 CSS 的必要性可能就不太明显

  1. 默认情况下,CSS被视为阻塞渲染的资源
  2. 我们可以通过媒体类型和媒体查询将一些CSS资源标记为不阻塞渲染
  3. 浏览器会下载所有CSS资源,无论阻塞还是不阻塞,所以阻塞渲染仅仅是指浏览器是否需要暂停网页的首次渲染,直至该资源准备就绪
<style>/* styles here */</style> 
{{-- link标签需要加一个网络来回的时间开销 --}}
<link href="style.css" rel="stylesheet">
<link href="print.css" rel="stylesheet" media="print">
<link href="other.css" rel="stylesheet" media="(min-width: 40em)">

几种引入CSS资源的方法,是否阻塞首次渲染

  • link引入,是
  • style标签直接写入,是
  • 通过DOM api引入, 否
const style = document.createElement('link');
style.rel = 'stylesheet';
style.href = 'index.css';
document.head.appendChild(style);
  • 使用preload方式载入CSS,否
<link rel="preload" href="index_print.css" as="style" onload="this.rel='stylesheet'">
  • 为link添加media query, 当媒体查询不匹配时,不会阻塞

注意

  • CSS选择器越详细,匹配工作越多,匹配节点越慢
  • renderTree只包含了渲染网页所需要的元素,不需要的是不会被添加进去的,比如<head>,display: none的节点
    设置了visibility:hidden的元素虽不可见,但仍然占有空间,仍会被添加到RenderTree
  • layout是指计算DOM元素在最终屏幕上显示的大小和位置,由于web页面的元素布局是相对的,所以任意其中一个元素的位置发生变化,都会联动其他元素,就会产生reflow(回流)
    • 屏幕旋转
    • 浏览器视窗改变,触发resize事件
    • 与大小和位置相关的CSS属性发生改变
    • 尽量不用table布局,可能很小的一个小改动会造成整个 table 的重新布局

repaint(重绘):节点需要更改外观,但不改变布局和几何属性,就叫做重绘,比如color

JS对渲染的影响

JavaScript 可以查询和修改 DOM 与 CSSOM

由于浏览器不了解脚本计划在页面上执行什么操作,它会作最坏的假设并阻止解析器。当 HTML 解析器遇到一个 script 标记时,它会暂停构建 DOM,将控制权移交给 JavaScript 引擎;等 JavaScript 引擎运行完毕,浏览器会从中断的地方恢复 DOM 构建。因此,执行内联脚本会阻止 DOM 构建,也就延缓了首次渲染

另外,由于JS可以读取和修改CSSOM属性
如果浏览器尚未完成 CSSOM 的下载和构建,这时遇到了脚本需要运行,浏览器将延迟脚本执行和 DOM 构建,直至其完成 CSSOM 的下载和构建

如果是外部 JavaScript 文件,浏览器必须停下来,等待从磁盘、缓存或远程服务器获取脚本,这就可能给关键渲染路径增加数十至数千毫秒的延迟

所以可以通过标记外部JS文件为异步(async/defer),指示浏览器在等待脚本可用期间不阻止DOM构建
f8467ebf-c260-4595-9b54-5a4d0ea0c9dd

另外,对于执行时间过长的JS代码,可以考虑用Web Worker去处理,它不会操作DOM元素,只能做一些纯计算的工作

JavaScript代码运行在浏览器的主线程上,但浏览器的主线程还负责样式计算、布局、绘制的工作,所以JS运行时间过长会阻塞其他渲染工作,导致丢帧,每帧的渲染应该在16ms内完成,而动画占据了不少时间,所以JS代码的运行消耗应该控制在3~4ms

其他资源的影响

构建渲染树甚至绘制网页时无需等待页面上的每个资产:并非所有资源都对快速提供首次绘制具有关键作用
谈论关键渲染路径时,通常谈论的是 HTML 标记、CSS 和 JavaScript。图像不会阻止页面的首次渲染

优化关键渲染路径

为尽快完成首次渲染,我们需要最大限度减小以下三种可变因素:

  • 关键资源的数量:可能阻止网页首次渲染的资源
  • 关键路径长度:获取所有关键资源所需的往返次数或总时间
  • 关键字节的数量:所有关键资源传送文件大小的总和

优化关键渲染路径的常规步骤如下

  • 对关键路径进行分析和特性描述:资源数、字节数、长度
  • 最大限度减少关键资源的数量:删除它们,延迟它们的下载,将它们标记为异步等
  • 优化关键字节数以缩短下载时间(往返次数)
  • 优化其余关键资源的加载顺序:您需要尽早下载所有关键资产,以缩短关键路径长度

PageSpeed 规则和建议

  • 消除阻塞渲染的 JavaScript 和 CSS
  • 优化 JavaScript 的使用
    • 首选使用异步 JavaScript 资源 async
    • 延迟解析 JavaScript defer
    • 避免运行时间长的 JavaScript,也就是常说的拆分代码
  • 优化 CSS 的使用
    • 将 CSS 置于文档 head 标签内,浏览器尽早发现 标记并尽早发出 CSS 请求
    • 避免使用 CSS import,它们会在关键路径中增加往返次数
    • 内联阻塞渲染的 CSS,不会增加关键路径中的往返次数