chrome渲染流程(一)

88 阅读5分钟

说明

  • 本文是极客时间-李兵【浏览器工作原理与实践】课程的学习记录
  • 有的内容是自己的理解,不排除有错误

序言
之前对chrome架构有了简单的了解,很多东西看上去和我目前的工作没什么太大关系。前端开发需要重点关注的就是渲染进程,我们开发的代码都是运行在此,所以来了解下吧!

渲染进程的输入是HTML、CSS、JS文本,输出位图,这个过程称为渲染流程。
渲染流程的处理是一条流水线,流水线的每个阶段都有其对应的输入内容、处理过程、输出内容。

1 构建DOM树

浏览器无法直接理解和使用HTML,需要将其转换为它能理解的结构——DOM树。

Xnip2022-09-22_09-05-46.jpg

js中的document对象就是DOM树 Xnip2022-09-22_09-38-10.jpg 这里看起来和html没什么不同,但html是个字符串,而它是存在于内存中的对象,有属性和方法,可通过js获取和修改。

树结构 Xnip2022-09-22_19-37-08.jpg 修改属性 Xnip2022-09-22_09-43-12.jpg

2 样式计算

有了DOM结构,还需要知道每个DOM节点中的具体样式,这个由样式计算(Recalculate Style)来完成。

2.1 将CSS文本转换为styleSheets

同样的,浏览器无法直接理解和使用CSS文本,会先将其转换为可以理解的结构——styleSheets

以这段代码为例,我们可以看到styleSheets的结构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,viewport-fit=cover" />
    <link rel="stylesheet" href="https://lf3-cdn-tos.bytescm.com/obj/static/xitu_juejin_web_editor/static/ionicons/css/ionicons.min.css">
    <style>
        #app {
            width: 300px;
            height: 400px;
            background-color: red;
            font-size: 16px;
            line-height: 1.5em;
            color: white;
        }
    </style>
    <style>
        #first-row{
            background-color:green;
        }
        #second-row{
            background-color: blue;
            font-size: 18px;
        }
    </style>
</head>
<body>
<div id="app">
    <div id="first-row">
        小桌呼朋三面坐
    </div>
    <div id="second-row" style="margin-top: 10px;">
        留将一面与梅花
    </div>
</div>
</body>
</html>

Xnip2022-09-22_20-48-54.jpg

  • StyleSheetList(样式表)由style标签数和link的css文件组成
  • 样式表中不包含节点的内联样式,内联样式在DOM节点的style对象中
Xnip2022-09-22_20-55-05.jpg

从数据中可以看出,CSSRules的数量就是style中选择器的数量,每一个CSSStyleRule对应一个选择器和它的样式。

2.2 标准化属性值

节点最后的样式可通过【计算样式】查看到
Xnip2022-09-22_20-58-26.jpg
可能有同学已经注意到了,这里的值和定义、styleSheets中的值不一样。这就是流水线的下一个操作——将属性值标准化
因为写样式的时候,可能支持很多属性值,比如颜色可以用white #fff,还有其它如em rem bold,这些数值都会先被转换为渲染引擎可以理解的、标准化的值。(标准化后的属性值并未出现在styleSheets中)

2.3 计算DOM节点的具体样式

已经有所有节点的结构和样式,且样式值已经标准化了,最后一步就是计算出DOM树中每个节点的具体样式
这一步输出的内容是每个DOM节点的样式,并保存在计算样式中(ComputedStyle)的结构内。(这个过程中会用到css的继承和层叠规则,这里就不展开了,学了css的大概都知道)

DOM节点中没有computedStyle这个属性,有个computedStyleMap方法

const el = document.getElementById('second-row');
Xnip2022-09-23_08-58-31.jpg

这个结果并不是直观的样式,我们还可以通过getComputedStyle这个方法来获取进一步的值。
Xnip2022-09-23_08-53-22.jpg
节点能有的属性都在,很多都是默认值,重点关注前面设置过的两个属性。(这个对象有342个属性,不过截图中没有截出来)。

总结一下,这条流水线的处理过程是 Xnip2022-09-23_09-23-28.jpg

这里我对流水线第2、3步有个不影响整体理解的小疑惑:我觉得这两个步骤的顺序应该相反才,又或者是第2步应该还包含对内联样式属性值的标准化。

DOM节点最终的样式来源有两个,DOM的style属性(内联样式)和styleSheets,style和styleSheets中的属性值都是原值,最后的计算样式的属性值是标准值。
如果第2步处理了styleSheets中的属性值,那style中的值什么时候处理?
如果styleSheets和style都要处理,不如直接先计算节点的具体样式,然后最结果的值再进行标准化。

3 布局

得到DOM树和每个节点的具体样式后,下一个就是计算出DOM树中可见元素的几何位置,这个过程就叫布局,有以下两个步骤。

3.1 创建布局树

DOM树中有所有的DOM节点,但有的节点本身不需要显示,比如headmeta标签。有点节点因为设置了display:none,也不用显示。所以在显示之前,需要先创建一个只有可见元素的布局树(有的地方叫Render树,应该指的是同一个)。

Xnip2022-09-23_21-10-16.jpg

这个处理结果只是用于页面渲染,属于一次性的,也不需要外部来操作,没有保存在内存中。

3.2 布局计算

得到布局树后,就需要计算树中节点的坐标了。
据说过程复杂,不过不了解也不影响啥,忽略。

Version:0.9 StartHTML:0000000105 EndHTML:0000000518 StartFragment:0000000141 EndFragment:0000000478

最后:如果下载CSS文件阻塞了,会阻塞DOM树的合成吗?会阻塞页面的显示吗?

  • 不会阻塞DOM树的合成
    从DOM的创建过程、结果中能知道生成DOM树和CSS文件的解析都没有关系。(既然都这样了,没道理开发的时候还让它来阻塞)
  • 会阻塞页面显示
    页面显示需要布局树,CSS文件下载会影响创建布局树,进而影响页面显示。

没测试,掘金上有位网友测试了比较多的场景,也有更多的结论,有兴趣点它css加载会造成阻塞吗?