yanyue404 / blog

Just blog and not just blog.
https://yanyue404.github.io/blog/
Other
88 stars 13 forks source link

从输入URL到页面加载的过程(下) #227

Open yanyue404 opened 2 years ago

yanyue404 commented 2 years ago

大纲

解析页面流程

前面有提到 http 交互,那么接下来就是浏览器获取到 html,然后解析,渲染

这部分很多都参考了网上资源,特别是图片,参考了来源中的文章

流程简述

浏览器内核拿到内容后,渲染步骤大致可以分为以下几步:

1. 解析HTML,构建DOM树

2. 解析CSS,生成CSS规则树

3. 合并DOM树和CSS规则,生成render树

4. 布局render树(Layout/reflow),负责各元素尺寸、位置的计算

5. 绘制render树(paint),绘制页面像素信息

6. 浏览器会将各层的信息发送给GPU,GPU会将各层合成(composite),显示在屏幕上

如下图:

HTML 解析,构建 DOM

整个渲染步骤中,HTML 解析是第一步。

简单的理解,这一步的流程是这样的:浏览器解析 HTML,构建 DOM 树。

但实际上,在分析整体构建时,却不能一笔带过,得稍微展开。

解析 HTML 到构建出 DOM 当然过程可以简述如下:

Bytes → characters → tokens → nodes → DOM

譬如假设有这样一个 HTML 页面:(以下部分的内容出自参考来源,修改了下格式)

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
  </body>
</html>

浏览器的处理如下:

列举其中的一些重点过程:

1. Conversion转换:浏览器将获得的HTML内容(Bytes)基于他的编码转换为单个字符

2. Tokenizing分词:浏览器按照HTML规范标准将这些字符转换为不同的标记token。每个token都有自己独特的含义以及规则集

3. Lexing词法分析:分词的结果是得到一堆的token,此时把他们转换为对象,这些对象分别定义他们的属性和规则

4. DOM构建:因为HTML标记定义的就是不同标签之间的关系,这个关系就像是一个树形结构一样
例如:body对象的父节点就是HTML对象,然后段略p对象的父节点就是body对象

最后的 DOM 树如下:

生成 CSS 规则

同理,CSS 规则树的生成也是类似。简述为:

Bytes → characters → tokens → nodes → CSSOM

譬如style.css内容如下:

body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }

那么最终的 CSSOM 树就是:

构建渲染树

当 DOM 树和 CSSOM 都有了后,就要开始构建渲染树了

一般来说,渲染树和 DOM 树相对应的,但不是严格意义上的一一对应

因为有一些不可见的 DOM 元素不会插入到渲染树中,如 head 这种不可见的标签或者display: none

整体来说可以看图:

渲染

有了 render 树,接下来就是开始渲染,基本流程如下:

图中重要的四个步骤就是:

1. 计算CSS样式

2. 构建渲染树

3. 布局,主要定位坐标和大小,是否换行,各种position overflow z-index属性

4. 绘制,将图像绘制出来

然后,图中的线与箭头代表通过 js 动态修改了 DOM 或 CSS,导致了重新布局(Layout)或渲染(Repaint)

这里 Layout 和 Repaint 的概念是有区别的:

回流的成本开销要高于重绘,而且一个节点的回流往往回导致子节点以及同级节点的回流, 所以优化方案中一般都包括,尽量避免回流。

什么会引起回流?

1.页面渲染初始化

2.DOM结构改变,比如删除了某个节点

3.render树变化,比如减少了padding

4.窗口resize

5.最复杂的一种:获取某些属性,引发回流,
很多浏览器会对回流做优化,会等到数量足够时做一次批处理回流,
但是除了render树的直接变化,当获取一些属性时,浏览器为了获得正确的值也会触发回流,这样使得浏览器优化无效,包括
    (1)offset(Top/Left/Width/Height)
     (2) scroll(Top/Left/Width/Height)
     (3) cilent(Top/Left/Width/Height)
     (4) width,height
     (5) 调用了getComputedStyle()或者IE的currentStyle

回流一定伴随着重绘,重绘却可以单独出现

所以一般会有一些优化方案,如:

再来看一个示例:

var s = document.body.style;

s.padding = "2px"; // 回流+重绘
s.border = "1px solid red"; // 再一次 回流+重绘
s.color = "blue"; // 再一次重绘
s.backgroundColor = "#ccc"; // 再一次 重绘
s.fontSize = "14px"; // 再一次 回流+重绘
// 添加node,再一次 回流+重绘
document.body.appendChild(document.createTextNode('abc!'));

CSS 的标签与 JS 的 Githubissues.

  • Githubissues is a development platform for aggregating issues.