组织严密的生产流水线——浏览器的渲染原理

130 阅读3分钟

image.png

浏览器的网络线程获取到 HTML 后,产生一个渲染任务,交给渲染主线程的消息队列,
在事件循环机制的作用下,渲染主线程取出渲染任务,开始以下 8 个主要的渲染流程:
事件循环机制详见《浏览器渲染进程模型——事件循环》

  1. 解析 HTML:
  • 主线程遇到 css 解析 css,遇到 js 执行 js。
  • 为提高效率,解析前浏览器还会开启一个预解析线程,用于提前下载外部的 css 和 js 文件并解析,因为是预解析线程所以 css 不会阻塞主线程,但 js 可能会修改页面所以阻塞主线程。
  • 完成后生成dom和cssom树
  1. 样式计算 style:
  • 主线程遍历 dom 树,计算最终样式,如预设值变成绝对值、相对单位变成绝对单位等。
  • 完成后生成带样式的dom树
  1. 布局 layout:
  • 主线程遍历带样式的 dom 树,计算几何信息,如宽高,相对包含块的位置。
  • 遍历完后生成布局树,不会和 dom 树一一对应,因为没有几何信息的 dom 节点不会生成到布局树,而 dom 节点中不存在的伪元素若有几何信息则会生成到布局树,还有布局树中额外添加的匿名行盒、匿名块盒等都会导致不和 dom 树一一对应。
  • 完成后生成布局树
  1. 分层 layer:
  • 主线程使用一套复杂的策略对整个布局树进行分层,实现按需修改提升效率。
  • 滚动条、堆叠上下文、transform、opacity、will-change等属性会影响分层结果。
  • 完成后生成多层结构
  1. 绘制 paint:
  • 主线程为每个层单独产生绘制指令集,用于描述该层内容如何画出来,类似 canvas 原理。
  • 完成后生成各层的指令集

主线程任务结束,后续由其他线程完成。

  1. 分块 tiling:
  • 合成线程对每个层进行矩阵分块,从而可以优先显示视口区域。
  • 此过程会从线程池分配多个分块器进行多线程同时工作。
  • 完成后生成各层的矩阵块
  1. 光栅化 raster:
  • 合成线程将块信息交给GPU进程,以极高速度完成光栅化。
  • 此过程也会分配多个线程,并优先光栅化视口区域。
  • 完成后生成各层的位图(包含像素信息)
  1. 画 draw:
  • 合成线程根据各层的位图生成一个个的指引quad信息。
  • 指引会标识每个位图应该画到屏幕哪个像素位置,以及 transform 变形信息。
  • transform 变形在此步骤才开始计算,把位图通过数学矩阵变换来实现各种效果。
  • 完成后生成指引quad

合成线程把全部指引提交给 GPU 进程,后续由 GPU 进程完成。
GPU 进程拿到指引 quad 后,产生系统调用,提交给 GPU 硬件,完成最终的屏幕成像。

image.png