浏览器解析 HTML 文件的过程
#
详细过程分析#
1)构建DOM树将HTML转换为浏览器能够理解的结构一-DOM 树
①HTML词法、语法的解析
- 词法分析:把字符流初步解析成我们可理解的"词",学名叫token。
- 语法分析:把开始结束标签配对、属性赋值好、父子关系连接好、构成dom树。
②请求js,css
#
2) 样式计算(Recalculate Style)- 把CSS转换为浏览器能够理解的结构-styleSheets;
- 转换样式表中的属性值,使其标准化;
- 计算出DOM树中每个节点的具体样式
- CSS继承,包含父节点的样式;
- 样式层叠的规则: !important 无限高>内联1000> id 100> class 10> tag >继承>浏览器默认
#
3) 布局阶段- 创建布局树L ayout tree, 构建一棵只包含 可见元素布局树; head标签, 不可见元素都不包含;
- 布局计算
#
4)分层页面中有复杂效果,如3D变换、页面滚动,或者使用z-indexing 做Z轴排序等,渲染引擎还需要为特定的节点生成专用的图层,并生成棵对应的图层树 (L ayerTree)。
图层树和布局树的关系,每一 个节点自己没有单独的图层,就属于父节点的图层,反正所有的节点都会直接或者间接地从属于一个层,
哪些节点会创建新的图层?
- 拥有层叠上下文属性的元素会被提升为单独的一层。比如:明确定位属性position: fixed、 定义透明属性opacity、使用CSS滤镜iter的元素、z-index
- 需要剪裁(clip) 的地方也会被创建为图层。比如div内容的文字超出div范围,会被裁剪,渲染引擎单独为文字部分单独创建-一个层; 如果出现滚动条,滚动条也会被提升为单独的层;
#
5) 图层绘制- 图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表 ;
- 可以在开发者工具的L ayers点击document的profiler查看到绘制列表;
#
6)合成线程进行分块- 主线程会把该绘制列表提交(commit) 给合成线程,进行真正的绘制;
- 合成线程会将图层划分为图块(tile) ,这些图块的大小通常是256x256 或者512x512
#
7)栅格化- 栅格化,是指将图块转换为位图。图块是栅格化执行的最小单位。渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的;
- 按照视口附近的图块来优先生成位图;
- 栅格化过程都会使用GPU来加速生成,使用GPU生成位图的过程叫快速栅格化,或者GPU栅格化,生成的位图被保存在GPU内存中;
#
8)合成和显示- 一旦所有图块都被光栅化,合成线程就会生成个绘制图块的命令- "DrawQuad",然后将该命令提交给浏览器进程 。
- 浏览器进程里面有一个叫viz的组件,用来接收合成线程发过来的DrawQuad 命令,然后根据DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。
#
通俗理解- 解析html: 通过字节流把内容传到html解析引擎, 解析引擎首先会调用解析器处理标签,处理没闭合或者使用不规范的标签,处理完毕后交给分词器处理。分词器将标签转换为token,并交给dom构建器处理。在解析过程中遇到script会暂停解析,直到script加载完成并执行完,html才会继续解析。
- 构建dom树。将token 解析为dom节点, 并将dom节点添加到dom树中。通过压栈出栈方式构建dom树。这个过程就是逐行解析代码,包括html标签 和js动态生成的标签,最终生成dom树。
- css树。 在解析的过程中,遇到css 资源需要加载时,htrml解析不会暂停。当css资源下载好,会调用css解析引擎去解析CSS代码,计算出最终的样式数据。对CSS代码中非法的语法她会直接忽略掉。解析CSS的时候会按照如下顺序来定义优先级:浏览器默认设置,用户设置,外链样式,内联样式,html中的style。 在解析css的同时,渲染树构建被暂停,直到css树解 析完成。
- 渲染树。把之前构建好的css树以及dom树按照-定的规则以及依赖关系生成渲染树,写到内存,等待进一 步生成界面。渲染树和dom树是有区别的。dom树完全和html标签一-对应, 但是渲染树会忽略掉不需要渲染的元素,比如head、 display:none的元素 等。
- 布局。从渲染树的根节点开始遍历,然后确定每个节点对象在页面上的确切大小与位置,布局阶段的输出是一个盒子模型,它会精确地捕获 每个元素在屏幕内的确切位置与大小。同时把每个节点做成一个纹理,放在gpu寄存器中管理
- 绘制。遍历渲染树,调用渲染器的paint()方法在屏幕上显示。