总的来说浏览器要经过一下几个步骤才能将下载好的数据渲染到浏览器界面上
DOM + CSSOM = Render Tree
- 处理 HTML 标记并解析为 DOM 树。(Parse HTNL)
- 处理 CSS 标记并解析为 CSSOM 树。(Recalculate style)
- 将 DOM 与 CSSOM 合并成一个渲染树。
- 根据渲染树来布局,以计算每个节点的几何信息。(layout)
- 将各个节点绘制到屏幕上。(panit & Composite Layers )
这其中将HTML文档解析为DOM与将特定样式表(stylesheet)的规则和资源解析为CSSOM是同步进行的。最终将两者(DOM CSSOM)合并为渲染树(这也意味着一般的css和html都是阻塞界面渲染的资源)此时浏览器就有了足够的信息在浏览器上执行布局(Layout)和绘制(Paint)。
不幸的是这只是没有引入js的情况
- 因为同步js脚本可以在任何时间使用document.write,因此DOM树构造将在任何时候遇到一个同步js标签时阻塞。
- 另一方面js可以获取任意节点对象计算样式,这就意味着js脚本也会被CSSOM构造阻塞。
添加同步js后,在js没执行完之前DOM构造被阻塞,在执行js之前CSSOM必须构造完成
文档 Interactive & DOMContentLoaded
- 当浏览器完成对所有 HTML 的解析并且 DOM 构建完成文档标记为Interactive。
- 当 DOM 准备就绪并且没有样式表阻止 JavaScript 执行。文档标记为DOMContentLoaded。此时DOM和CSSOM均准备就绪开始合成render tree。 (这是有有阻塞解释器js的情况,包括同步和含有defer属性js)
note:如果没有阻塞解析器的 JavaScript,则 DOMContentLoaded 将在 domInteractive 后立即触发。同时也意味着无需等待样式表完成加载和解析。
关于css的渲染阻塞
- 默认情况下,CSS 被视为阻塞渲染的资源
- 我们可以通过媒体类型和媒体查询将一些 CSS 资源标记为不阻塞渲染。
1
2
3<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 资源,无论阻塞还是不阻塞。
关于js的DOM阻塞
- JavaScript 可以查询和修改 DOM 与 CSSOM。
- JavaScript 执行会被 CSSOM 的构造阻塞
- 除非将 JavaScript 显式声明为异步,否则它会阻止构建 DOM。
1
2
3
4
5
6
7
8
9
10
11
12<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<title>Critical Path: Script Async</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
<script src="app.js" async></script>
</body>
</html> - 执行我们的内联脚本会阻止 DOM 构建,也就延缓了首次渲染。
- 浏览器将延迟脚本执行和 DOM 构建,直至其完成 CSSOM 的下载和构建。
优化关键渲染路径
- 对关键路径进行分析和特性描述:资源数、字节数、长度。
- 最大限度减少关键资源的数量:删除它们,延迟它们的下载,将它们标记为异步等。
- 优化关键字节数以缩短下载时间(往返次数)。
- 优化其余关键资源的加载顺序:您需要尽早下载所有关键资产,以缩短关键路径长度。