渲染流程

102 阅读5分钟

进程线程

  • 什么是进程

一个进程就是一个程序运行的实例。

启动一个程序,操作系统为其分配一块内存,内存中有代码,数据和程序的主线程 PCB 控制块等等。

这样的一个运行环境叫做进程,是资源分配和调度的单位,是 CPU 占用的单位(时间片轮转法+动态优先级)。

MAC 的活动监视器的 “内存” 视角就是内存的分配单位 “进程” 的列表,每个进程有多个线程和一块内存和一个端口,PID 为进程号。

  • 线程

单线程就是这个进程只有一个线程,线程是 CPU 调度的最小单位,一个进程下的线程共享进程内存空间,线程的调度是应用层问题,程序进程自己负责,不需要内核的介入。

JS 属于一种单线程语言,一个完整的同步任务执行完毕后才能进行下一步操作,这也是为什么说浏览器脚本执行会阻塞视图更新。

浏览器

现代浏览器是多进程的。

如果单线程浏览器(就连 IE 都是每个标签页新开一个 IE 执行的):

  • 一个线程崩了就全崩了
  • 页面之间相互阻塞任务
  • 页面能拿到整个浏览器的数据
  • 浏览器进程中的页面共享进程:浏览器主进程(里面还有IO,file等线程可能未来分离出进程),网络进程,CPU 进程
  • 沙箱中的进程:插件进程 / 页面的渲染进程(renderer)
  • 同站进程共享:同一个站点的不同页面会相互调用脚本共用进程,有时仍然导致一个页面崩了牵连全崩(比如 BroadCast Channel,service worker, shared worker 等 API 可以实现同源页面通信)

Renderer 进程

页面渲染进程是多线程的,如

JS 引擎线程, HTTP 请求线程,定时器线程,GUI 线程,时间处理线程(event 队列)

  • GUI 处理 html 构建 domtree
  • stylesheets 层叠样式表:格式化 - 标准化 - 计算优先级确定节点样式
  • 整合 domtree + csstree = 渲染树 (DOMnode + nodestyle)
  • 根据渲染树,计算节点布局 ( 每个节点的位置 ,layout 树,回流/重排)
  • 生成图层树 (layer tree)(以此开始以下流程:repaint 重绘)
  • 对每个图层,生成绘制指令(数据命令),commit 这些指令给合成线程绘制。
  • 合成线程将每个图层分成若干个图块,根据图块的位置优先级将指令栅格化为位图
    • 会有一个栅格化子线程池不断的栅格化图块
    • 会调用 GPU 加速快速栅格化并将位图保存在显存中
    • (栅格化即将矢量绘制指令转为像素位图)
  • 栅格化的成果是绘制命令(图形命令)交给浏览器进程,浏览器根据这些指令把页面绘制后发给显卡缓冲区
  • 显示器在下一次刷新时将缓冲区图像打在显示器上(掉帧现象就是我要刷新了缓冲区的新图像没算出来)

DOM 树

  • 拿到文件的原始字节码,解析成 html5 标准文法。
  • 进行词法分析,得到 dom 节点对象
  • 构建 dom 树:根据文法标签的节点间关系构建树形数据结构。

( DOMContentLoaded & $(doucument).ready )

CSSOM 树

  • css 的计算会阻塞视图,视图的渲染需要 cssom 结果。
  • cssom 的构建很消耗性能,而过程中最消耗性能的样式的层叠深度。
  • 层叠底层:userAngent 用户代理样式表
  • 词法分析:格式化 - 标准化 - 计算优先级

Render 树

  • 合并 domTree CSSOMTree ,render tree 包含所有 dom 节点和其样式信息
  • 从根部遍历每个 domNode,忽略 link 等非可视节点,忽略 display:none 等不可见节点,每个可见节点在 cssomTree 中找到对应样式,并合并出结果生成 renderTree 的一个节点。

layout 回流(重排 reflow)

  • rendererTree 中每个节点和他对应的样式,节点之间的关系已经确定,根据这些数据计算他们相对于 viewport 的位置和大小,生成每个节点实际占用的绝对像素值。

图层树(从这里开始的以下:重绘 repaint)

  • 绘制时以图层为单位填充后再压叠。
  • 各种 FC 如 BFC 等是平面上的各种元素的排列布局,图层则是垂直方向上的排列布局,两个维度,在layout 树生成时已经完成的各种 FC 的计算,而图层数据则是 layout 树中各个节点的一个属性。
    • fiexd 定位,既在平面上生成了新的 BFC 使得在平面上布局独立,也生成了新的高优先级图层。
    • z-index 属性,改变了节点的图层压叠优先级,但没生成新的 BFC。
  • 浏览器一般会对一些影响 rendererTree 较大的节点放在单独的层。

合成 compositing

  • 以图层为单位,根据其中节点的绝对像素位置,将其分为图块,图块根据在 viewport 中的相对位置具有不同的优先级,高优先级的图块有限被送至合成线程池(可调用 GPU)进行栅格化,把适量图像信息计算成像素位图。
  • 将图块位图结果存在显存中,合成线程收集图块结果中绘制四边形(draw quads 储存位图的位置)信息,选择需要的图块进行合成(图块合成图层并压叠)得到一个完整的渲染帧,合成线程通过 IPC 向浏览器主进程 commit 一个渲染帧。
  • “快速滚动区”的滚动操作触发时,合成线程可以独立生成新的渲染帧而不需要等待上级的命令。
    • 快速滚动区:页面中没有事件绑定的区域。或有事件但事件属性有 passive: true

尾声

  • 浏览器主进程收到新的渲染帧,调用显存中的位图结果,压入显卡缓冲区,在下一个刷新时机调换活动区和缓冲区。