- Published on
浏览器渲染原理
浏览器渲染原理
当浏览器网络进程获取到 HTML 文件后 会产生一个渲染任务 并将这个任务放入消息队列 事件循环会开启渲染任务
1、解析 HTML 形成 DOM 树 CSS 树
解析过程中如果遇到了 css 就解析 css 遇到了 js 就解析 js 浏览器在解析前会开一个预解析线程去下载并解析外部的(link)的 css 和 js 文件
浏览器渲染主线程解析到了 link,如果 css 还没下载解析好,浏览器并不会等待,继续解析 dom,因为下载解析都是在预解析线程完成的 这就是 css 不会阻塞 dom 树形成的根本原因
但是当遇到 script 标签后,会停止解析 html(阻塞),等待网络线程下载好 js 文件并执行(js 可能会改变 dom 的位置),这是 js 会阻塞 html 解析的原因
2、样式计算(重排)
主线程会遍历得到的 dom 树 依次为树中的节点计算出他的最终样式 (Computed Style),在这个过程中值会统一 比如 white 变成 rgb(255,255,255) em 变成计算后得到的 px
3、布局
- html 只是语义化 样式都是 css 决定的
- 为什么 div display block 因为浏览器底层写了 div 的样式 display:block
- 内容必须在行盒中 行盒和块盒不能相邻 匿名行盒 匿名块盒的存在和其它一些原因都不能导致 dom 树和布局树不能一一对应
- 类似距顶的高度宽度都是布局树给的信息
4、分层
- 主线程会对布局树进行分层
- 好处在于性能的提升但是会占内容 ,某一个层的改变不会影响其他图层,尽改变当前层
- z-index opacity transform 会影响分层结果 通过 will-change 属性可以较大的影响分层结果
- 滚动条是单独的一层
5、重绘
6、分块(至此交给合成线程与渲染主线程无关)
7、光栅化
- 合成线程会将块信息交给 GPU 进程,以极高的速度进行光栅化
- GPU 进程会开启多个线程来完成光栅化,并且优先处理靠近视口的块。
- 光栅化的结果就是一块一块的位图
8、画
- 合成线程拿到每个层 每个块的信息后,生成指引信息
- 指引会标识出每个位图应该画到屏幕的哪个位置,以及会考虑到旋转,变形
- transform 发生在合成线程 与渲染主线程无关 这是他性能高的根本原因
- 合成线程会把指引信息提交给 GPU 最终完成屏幕中的图像
什么是 reflow?
- reflow 的本质就是重新计算 layout 树。
- 当进行了会影响布局树的操作后,需要重新计算布局树,会引发layout。
- 为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当 JS 代码全部完成后再进行统一计算。所以,改动属性造成的 reflow 是异步完成的。
- 也同样因为如此,获取布局属性时,就可能造成无法获取到最新的布局信息。
- 浏览器在反复权衡下,最终决定获取属性立即 reflow。