JavaScript面试题14-浏览器的渲染流程?
文章标签:
html 渲染
第一步:解析 HTML
- 解析过程中遇到 CSS,解析 CSS;遇到 JS ,执行 JS;为了提高效率,浏览器在开始解析之前,会启动一个预解析线程,率先下载 HTML 中外部的 CSS 文件和外部的 JS 文件;
- 如果主线程解析到 link位置时,此时外部的 CSS 文件还没有下载解析完成,主线程不会等待,继续执行后续代码,因为 CSS 下载和解析工作是在预解析线程中进行的,这也是CSS不会阻塞 HTML 解析的根本原因
- 如果主线程解析到 script 位置时;会停止解析 HTML,而去等待 JS文件下载完毕,并将全部代码执行完成后,才会继续解析 HTML;这是因为 JS 代码在执行的过程中有可能会修改当前的DOM树;所以DOM 树的生成必须停止,这也就是 JS 会阻塞HTML 解析的根本原因;
第二步:样式计算
- 主线程会遍历得到的 DOM 树;依次为每个 DOM 树的节点计算出最终样式;
- 在这一过程中,很多相对值会变成绝对值;例如:16进制颜色值会变成rgb颜色值,rem、em、vw会变成px;
- 第三步:布局
- 布局阶段主线程会依次遍历 DOM 树的每一个节点,计算每一个节点的几何信息;例如节点的宽、高、相对包含块的位置;
- 大部分的时候 DOM(元素) 树和 Layout(布局)树并非一一对应;
- 例如display:none的节点是没有几何信息的;因此不会产生Layout树、使用了伪元素的选择器、虽然DOM树中不存在这些伪元素节点,但是它们拥有几何信息,所以会生成Layout树、还有匿名行盒、匿名块盒都会导致DOM树和Layout树无法一一对应;
- 内容必须在行盒中,盒子的类型有CSS来决定,不由HTML来决定,HTML只提供语义化;
第四步:分层
- 主线程会通过一套复杂的策略来对整个Layout树进行分层;
- 分层的好处在于将来某一个层改变后,仅会对该层进行后续处理,不会影响到其它层;从而达到提升效率
- 滚动条、堆叠上下文、transform、opacity等样式都会或多或少的影响分层结果,也可以通过will-嫦娥属性来更大程度上影响分层结果。
第五步:绘制
- 主线程会为每个层单独产生绘制指令集,用于描述这一层的内容如何画出来;
- 绘制完成后,主线程将每个图层的绘制信息提交给 合成线程,剩余的工作将由合成线程完成。
第六步:分块
- 合成线程首先对每个图层进行分块,将其划分为更多的小区域;
- 它会从线程池中拿取更多的线程来完成分块工作;
第七步:光栅化
- 分块完成后,合成线程将块信息交给GPU进程,以极高的速度完成光栅化;
- GPU 进程会开启多个线程来完成光栅化,并且优先处理靠近视口区域的块;
- 光栅化的结果就是一块一块的位置;
第八步:
- 合成线程拿到层,每个块的位图后,生成一个个【指引(quad)】信息;
- 指引会标识每个位图感应该画到屏幕的哪个位置,以及会考虑旋转,缩放等变形;
- 变形发生在合成线程,与渲染主线程无关,这就是transform效率高的本质原因;
- 合成线程会把quad提交给GPU进程,由GPU进程产生系统调用,提交给GPU硬件,完成最终的屏幕成像。