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。