hxh

理解关键渲染路径

hxh · 2017-02-02翻译 · 764阅读 原文链接

当浏览器接收到服务端响应的 HTML 页面时,在屏幕绘制图像之前发生了许多事情。浏览器初次绘制页面的过程称为“关键渲染路径”。

了解 CRP (关键渲染路径)对于理解如何提高网站性能非常有帮助。CRP 有 6 个阶段:

  1. 构建 DOM 树
  2. 构建 CSSOM 树
  3. 运行 JavaScript
  4. 创建渲染树
  5. 布局
  6. 绘制

Diagram of the Critical Rendering Path Sequence

1. 构建 DOM 树

DOM(文档对象模型 Document Object Model)树是代表 HTML 页面完全解析的对象。从根元素<html>开始,为页面的每个元素/文本创建节点。嵌套在其他元素中的元素表示为子节点,每一个节点都包含了该元素的所有属性。例如,一个<a>元素与它相关的节点都拥有href属性。

以示例文档为例:

<html>
<head>
  <title>Understanding the Critical Rendering Path</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header>
      <h1>Understanding the Critical Rendering Path</h1>
  </header>
  <main>
      <h2>Introduction</h2>
      <p>Lorem ipsum dolor sit amet</p>
  </main>
  <footer>
      <small>Copyright 2017</small>
  </footer>
</body>
</html>

将创建以下 DOM 树:

DOM Tree

HTML 的一个好处是,它可以部分执行。在页面中,文档不需要加载完全才开始展示。然而,其它资源,CSS 和 JavaScript,会阻塞页面的渲染。

2. 构建 CSSOM 树

CSSOM (CSS 对象模型 CSS Object Model)是代表 DOM 样式的对象。它的表现类似于 DOM,但表示的是每个节点的关联样式,不管是显性声明还是隐性继承的,都包含其中。

上文中文档引用的style.css文件中,包含以下样式:

body { font-size: 18px; }

header { color: plum; }
h1 { font-size: 28px; }

main { color: firebrick; }
h2 { font-size: 20px; }

footer { display: none; }

将创建以下 CSSOM 树:

CSSOM Tree

CSS 被认为是 “渲染阻塞资源”。这意味着资源解析完全才能构建渲染树(见下文)。与 HTML 不同,由于 CSS 具有继承的级联性质,不能局部使用。文档中后定义的样式会覆盖和改变先定义的样式。因此,如果我们在完全解析样式表之前就使用了样式表中定义较前的 CSS 样式,我们可能会应用了错误的 CSS。这意味着在我们进行下一步之前 CSS 必须解析完全。

CSS 文件仅仅应用于当前设备时才被认为是阻塞的。<link rel="stylesheet">标签可以接受media属性,指定应用样式的媒体。例如,在样式表中含有 orientation:landscape的 media 属性,但我们是在纵向模式下浏览的页面的,那么 CSS 资源就被认为是不阻塞的。

CSS 同时也是“脚本阻塞”。这是因为 JavaScript 文件必须等待 CSSOM 构建完才能运行。

3. 运行 JavaScript

JavaScript 被认为是“解析阻塞资源”。这意味着 JavaScript 会阻塞 HTML 文档的解析。

当解析到<script>标签时,不管是内联的还是外联的,它会停止获取(如果是外联的),立即运行。这就是为什么,如果文档包含一个 JavaScript 文件时,它必须放在文档之后。

为了避免 JavaScript 阻塞解析,可以应用async属性使它异步加载。

<script async src="script.js">

4. 创建渲染树

渲染树是 DOM 和 CSSOM 的结合。是代表最终渲染在页面上的内容的树。这意味着它只捕获可见内容,不包含如使用了display: none的不可见元素。

使用上文中的 DOM 和 CSSOM,创建以下的渲染树。

Render Tree

5. 布局

5. Generating the Layout

布局决定了视窗的大小,CSS 样式取决于它提供的上下文,如百分比或者视窗单位。视窗尺寸由文档头部的 meta 视窗标签决定,如果没有提供该标签,那么默认宽度为 980px。

例如,最常用的 meta 视窗值是设置为设备的尺寸。

<meta name="viewport" content="width=device-width,initial-scale=1">

如果用户用 1000px 宽的设备访问网页,那么尺寸就基于这个单位。视窗的一半则是 500px,10vw则是 100px,等等。

6. 绘制

最后,在绘制步骤中,页面的可见内容可以转换为在屏幕上显示的像素。

绘制所消耗的时间取决于 DOM 的大小和所应用的样式。有的样式会比其它样式需要更多的执行工作。例如,一个复杂的渐变背景图比一个简单的纯色背景图需要更多的时间。

联合起来

我们可以在开发者工具中查看进程中的关键渲染路径。对于 Chrome,在 Timeline 标签中(对于 Canary,很快成为 Chrome 的稳定版,重命名为 Performance)。

举个例子,上文示例的 HTML(添加了<script>标签):

<html>  
<head>  
  <title>Understanding the Critical Rendering Path</title>
  <link rel="stylesheet" href="style.css">
</head>  
<body>  
  <header>
      <h1>Understanding the Critical Rendering Path</h1>
  </header>
  <main>
      <h2>Introduction</h2>
      <p>Lorem ipsum dolor sit amet</p>
  </main>
  <footer>
      <small>Copyright 2017</small>
  </footer>
<script src="main.js"></script>
</body>  
</html>

如果查看页面加载的事件日志,我们会得到如下结果:

Performance Timeline

  1. 发送请求 - 发送 GET 请求 index.html

  2. 解析 HTML发送请求 - 开始解析 HTML 和构建 DOM。发送 style.css 和 main.js 的 GET 请求

  3. 解析样式表 - 创建 style.css 的 CSSOM

  4. 分析脚本 - 分析 main.js

  5. 布局 - 基于 HTML 的 meta 视窗标签布局

  6. 绘制 - 绘制文档

基于这些信息,我们可以决定如何去优化关键渲染路径。我会在下一篇文章中讨论这些技巧。

相关文章