1. 浏览器真正关心的是数据,而不是流程

不要记:

1
2
3
4
5
6
7
8
9
10
DOM


Layout


Paint


Composite

应该记:

1
2
3
4
5
6
7
8
9
10
DOM Node


LayoutObject


PaintArtifact


CompositorFrame

每一步都是:

输入 → 计算 → 输出新的数据。


2. 每个阶段负责什么

① DOM Node

职责:

  • 保存 HTML 结构
  • 父子关系
  • 属性(Attribute)

例如:

1
<div>Hello</div>

对应:

1
2
Node(div)
└──Node(text)

DOM 不负责:

  • x
  • y
  • width
  • height
  • 绘制

② Style(Computed Style)

职责:

保存元素最终样式。

例如:

1
2
3
4
background:red;
color:white;
width:100px;
font-size:16px;

这里只负责:

元素应该长什么样。

不负责:

放在哪里。


③ LayoutObject

职责:

保存布局结果(Geometry)。

例如:

1
2
3
4
5
6
7
8
9
x

y

width

height

baseline

Layout 的作用:

根据 Style 计算几何信息。

Layout 的输出:

1
LayoutObject

④ Paint

输入:

1
2
3
4
5
6
7
8
9
Geometry(LayoutObject)

+

Style

+

Layer 信息

Paint 做什么?

把每个 Layer 画出来。

输出:

1
PaintArtifact

可以理解成:

1
2
3
4
5
6
7
8
9
10
11
Layer1



Bitmap1

Layer2



Bitmap2

不是最终屏幕。


⑤ Composite

输入:

1
所有 Layer 的 PaintArtifact

负责:

  • 合成 Layer
  • transform
  • opacity
  • z-index
  • GPU 合成

输出:

1
CompositorFrame

最终交给 GPU。


3. 数据流

真正应该记住的是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
HTML


DOM Node


Computed Style


LayoutObject


PaintArtifact


CompositorFrame


GPU


Screen

4. Dirty(失效)机制

浏览器不是:

从头重新执行。

而是:

找到最早失效的数据。

然后:

1
从这里重新开始

例如:


修改 background

1
div.style.background="red";

影响:

1
2
3
4
5
6
7
8
9
Style Dirty



Paint Dirty



Composite Dirty

不会:

1
Layout Dirty

因为:

Geometry 没变。


修改 width

1
div.style.width="200px";

影响:

1
2
3
4
5
6
7
8
9
10
11
12
13
Style Dirty



Layout Dirty



Paint Dirty



Composite Dirty

因为:

Geometry 改了。


修改 transform(独立 Layer)

1
div.style.transform="translateX(...)";

影响:

1
Composite Dirty

通常:

1
2
3
4
5
6
7
8
Layout

×

Paint

×


5. LayoutObject 不是 DOM

DOM:

1
<div>Hello</div>

DOM:

1
2
3
4
5
div



text

Layout:

1
2
3
4
5
LayoutBlock



LayoutText

职责不同:

DOM:

HTML 结构

LayoutObject:

几何信息


6. 为什么需要 LayoutObject?

因为:

DOM 不应该保存:

1
2
3
4
5
6
7
width

height

x

y

这些属于:

Layout。

所以 Blink:

1
2
3
4
5
Node



LayoutObject

而不是:

1
2
3
4
5
6
7
8
9
Node

(width)

(height)

(x)

(y)

7. 不是每个 DOM Node 都有 LayoutObject

例如:

1
2
3
4
5
<div>
Hello
<!-- comment -->
<script></script>
</div>

DOM:

1
2
3
4
5
6
7
div

text

comment

script

LayoutObject:

1
2
3
LayoutBlock(div)

LayoutText(text)

Comment:

×

Script:

×

原因:

它们不会参与布局。


8. Paint 不创建 Layer

顺序是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Render Tree



Layout



Layer 决策



Paint



PaintArtifact



Composite

Paint:

使用 Layer。

不是:

创建 Layer。


9. Paint 的输入与输出

输入:

1
2
3
4
5
6
7
8
9
Geometry

+

Style

+

Layer

输出:

1
PaintArtifact

可以理解为:

1
2
3
Layer1图片

Layer2图片

Composite:

就是组合这些图片。


10. 删除一个 DOM 节点发生什么?

例如:

1
box.remove();

立即:

1
2
3
4
DOM Node

×

对应:

1
2
3
4
LayoutObject

×

下一次 Rendering Opportunity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
旧 PaintArtifact



失效



重新 Paint



新 PaintArtifact



重新 Composite

不是:

Paint 对象删除。

而是:

Paint 的结果失效,重新生成。


11. 当前已经建立的完整模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
HTML


DOM Node


Computed Style


LayoutObject


PaintArtifact


CompositorFrame


GPU


Screen

每一次修改,本质都是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
修改数据



判断哪些数据失效



从最早失效的数据开始重新计算



生成新的数据



显示到屏幕