Life of a Pixel 演讲的学习笔记。浏览器的渲染过程极为的复杂,演讲的语速也特别的快,因此若有错误请及时指出。css
前端的全部代码统称为Content,好比html,js,css,图片,视频等。html
在Chromium代码架构上Content命名空间包含了,黄色框内的全部内容。在Chromium代码中由WebContent类表示,WebContent类中封装了渲染进程。前端
Chromium是Google的开源项目,Chrome浏览器就是基于Chromium代码实现,Edge,Opera也是基于Chromium代码。git
Blink是浏览器排版引擎,属于Chromium中的一部分。Blink属于Content中渲染过程代码的子集。github
总结一下:在Chromium中WebContent类负责Content的渲染,渲染过程交由Blink实现web
parsing(解析HTML)-> style (生成样式规则模型) -> layout(生成布局对象)-> compositing update (输入合成)-> paint(绘制)-> commit(提交)-> tiling(切割)-> raster(栅格化)-> draw quads -> display(显示到屏幕上)浏览器
浏览器并不能只靠本身将网页渲染到屏幕上,浏览器的渲染须要使用底层操做系统提供的图形库,好比OpenGL API。可是OpenGL并不认识Html,Css这些内容,因此须要经过浏览器的Web Content须要将Html,Css转换成OpenGL能够识别的内容,而后经过OpenGL渲染到屏幕上。缓存
在渲染到屏幕以后,须要监听并响应,JavaScript,用户输入,异步加载,动画,滚动,缩放,而后进行渲染更新。对于一些更新渲染,是不须要从头走彻底部的渲染流程的。网络
从网络请求开始,最早获取的是html文件,因此浏览器渲染的起点,是HTML解析器。同时HTML中引入了CSS,JS,图片等资源,浏览器也会加载它们。架构
HTML文件的解析过程:
HTML文件 -stream-> HTMLDocumentParser(HTML文档解析器)-> HTMLTreeBuilder(HTML树构建器)-> DOM
DOM是基于HTML的倒着的树形结构,DOM有两个做用:
CSS样式表的解析过程:
CSS样式表 -> CSSParser(CSS解析器)-> 样式规则模型(Style Rule Model)
CSS样式是如何做用与DOM的?
根据已经解析的样式规则(Style Rule),和浏览器的默认样式,计算出每个DOM的样式。样式和属性值存储在一个巨大的ComputedStyle对象中。ComputedStyle对象是属性和属性值的映射。ComputedStyle对象中会挂载元素,应对应不一样元素的不一样样式。
在构建完DOM并完成样式计算后,须要肯定全部元素的几何形状(几何形状所占的区域以及坐标),这些布局信息称为LayoutObject对象,
布局对象(LayoutObject)保存布局树中,并与DOM关联。不一样的节点,对应不一样的布局类。可是不一样布局类都继承自LayoutObject这个父类。
LayoutObject对象和DOM元素并非一一对应的。好比当DOM元素的样式是display: none
时,是没有LayoutObject对象的。
输入合成阶段,咱们在下面讲🍵
根据布局对象(LayoutObject),绘制操做会将绘制操做记录在一个待显示项目列表(display items list)中。
什么是绘制操做?好比,根据布局对象(LayoutObject)在指定区域绘制一个红色的矩形。这就是绘制操做。
每个布局对象(LayoutObject)对应多个待显示项目,由于可能涉及到绘制不一样的部分。目前只是记录绘制操做,还没有执行绘制操做。绘制的顺序,受控于z-index
属性。
提交,分割阶段,咱们在下面讲🍵
待显示项目列表中绘制的实际操做,是由栅格化进程执行的。
栅格化会将待显示项,转换为颜色值的位图(将图像的信息,以像素为单位记录,记录每个像素点的颜色信息rgba值)。位图信息保存在内存中(一般是显存中)。gpu也能够将待显示项目列表栅格化,咱们称为gpu加速。此时位图信息还保存在显存中,没有输出到屏幕上。
对于图像信息,栅格化会对图像进行解码,获取位图信息。
栅格化的过程是经过SKIA库调用OpenGL API完成的。
SKIA是一个开源的图形引擎,SKIA能够实现栅格化,PDF输出,GPU加速。
draw quads阶段,咱们在下面讲🍵
SKIA产生OpenGL调用,使用命令缓存区的形式,传输到GPU进程,GPU接受到命令缓存,产生GL调用。像素被渲染到屏幕上了。
commit(提交)-> tiling(切割)-> raster(栅格化)-> draw quads -> display(显示到屏幕上)
渲染不是静态的,JavaScript,用户输入,异步加载,动画,滚动,缩放,都会改变渲染。从头执行渲染流程代价会很昂贵。若是每一秒低于60fps,就会变得卡顿。
为了不从头执行整个渲染流程,经常使用的优化方法就是标记出,发生了改变的部分,复用没有改变的部分。好比一个节点须要从新计算样式,在下一帧的时候,只从新计算该节点的样式。
Chrome另外的优化手段是分层
动画,滚动,缩放,操做都会建立图层。单独的合成线程,会对滚动输入操做,进行单独处理。
while(true) {
}
复制代码
当咱们使用js阻塞主线程时,因为单独的合成线程的存在,合成线程会对用户的滚动操做进行处理,虽然主线程被阻塞可是页面依然能够滚动
图层的存储结构也是树的形式,图层树间接的基于布局树。
compositing update(输入合成)阶段发生在Layout(布局)阶段以后,Paint(绘制)阶段以前。对页面进行分层,每一个图层被分别绘制。绘制阶段存在的待显示项目列表(display items list),其实不一样的图层拥有不一样的待显示项目列表(display items list)
绘制完成后,经过同步主线程的状态,更新合成线程图层的状态,最后同步回主线程
Raster会将待显示项目列表(display items list)转换为位图,可是有时候图层会很大,Raster又是一个开销很大的步骤,合成线程会将图层分割为图块,图块是Raster的基本单位。距离视口越近,会优先建立图块优先被栅格化。
图块会在单独Raster线程中栅格化
在绘制完全部图块以后,合成器线程将生成draw quads
,draw quads
是绘制图块的指令,draw quads
被包装在合成器框架对象中,提交给浏览器进程。
浏览器进程,运行显示合成器的组件,合成器组件调用OpenGL绘制draw quads
,最后像素在用户的屏幕上可见。