概述

在分析浏览渲染过程之前,我们先了解进程和线程:

  • 什么是进程?

    进程是CPU进行资源分配的基本单位

  • 什么是线程?

    线程是CPU调度的最小单位,是建立在进程的基础上的运行单位,共享进程的内存空间

那么我们可以得出结论:进程会占用系统资源,在一个进程内可以存在一个或多个线程,这就是单线程和多线程,但是无论是单线程还是多线程,都是在一个进程内。

多进程

浏览器进程
由上图我们可以知道:

1
2
3
4
5
- 浏览器是多进程的

- 不同类型的标签页都会开启一个新进程

- 相同类型的标签页会合并成一个进程

上图中浏览器各个进程的主要作用如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
- 浏览器进程 
1. 负责管理各个标签页的创建与销毁
2. 负责浏览器的界面显示和功能(前进,后退,收藏等)
3. 负责资源的管理与下载

- 第三方插件进程
1. 负责每个第三方插件的使用,每个第三方插件使用时候都会创建一个对应的进程

- GPU进程
1. 负责3D绘制和硬件加速

- 浏览器渲染进程 (本文主要分析)
1. 浏览器内核,主要负责HTML,CSS,JS等文件的解析和执行

浏览器内核

浏览器内核就是浏览器渲染进程,从接收下载文件后再到呈现整个页面的过程,由浏览器渲染进程负责,主要的流程如下:

  1. 解析HTML文件和CSS文件,加载图片等资源文件,渲染成用户看到的页面

  2. 执行解析js文件脚本代码

(本文主要讲解浏览器页面渲染过程,js脚本解析执行过程,我将会另开文章分析,所以本文有关js解析的内容都会省略)

在该过程中浏览器渲染进程会开启多个线程协作完成,主要的线程以及作用如下:

  1. GUI渲染线程

    • 负责解析HTML文件构建DOM树,解析CSS结合DOM树渲染成RenderObject树,然后布局和绘制页面

    • 当RenderObject树需要更新样式属性时,即发生重绘(Repaint)或RenderObject树中的元素规模尺寸,布局或显示隐藏等发生改变,即发生回流(reflow)时执行

  2. JS引擎线程

  3. 事件触发线程,

  4. 定时器触发器线程

  5. 异步http请求线程

注:GUI渲染线程与JS引擎线程是互斥的,因为JS引擎线程在执行过程中可能会发生重绘和回流,所以GUI渲染线程执行时候,JS引擎线程会被挂起,等待GUI渲染线程执行完毕才会执行;JS引擎线程执行时候同理

GUI渲染线程

接下来我们主要分析GUI渲染线程执行的详细过程:

1
2
3
4
5
6
7
8
9
1. 解析HTML文件,构建DOM树,同时浏览器主进程负责下载CSS文件

2. CSS文件下载完成,解析CSS文件成树形的数据结构,然后结合DOM树合并成RenderObject树

3. 布局RenderObject树,负责RenderObject树中的元素尺寸,位置等计算

4. 绘制RenderObject树,绘制页面的像素信息

5. 浏览器主进程将默认图层和复合图层交给GPU进程,GPU进程再将各个图层合成(composite),最后显示出页面

注:

  • 默认图层指的就是处于普通文档流的元素;

  • 复合图层一般指使用动画执行或者<video><iframe><canvas><webgl>等元素,也可以使用z-index将层级高的元素变成复合图层,使用复合图层可以进行硬件加速,其原理就是避免了默认图层的重绘和回流,想了解的童鞋可以自行深入研究。

了解GUI渲染线程的执行过程后,我们可以根据其渲染原理进行渲染优化:

  • 尽可能提前引入css文件,例如在头部引入css文件;

  • 尽可能早加载css文件中引用的资源,例如自定义字体文件,可以使用预加载,在link标签加入’rel=”preload” as=”font”‘该元素属性,不然会造成渲染阻塞

  • 在DOM和CSS渲染之后加载js文件,例如在尾部加载js文件,或者使用该元素属性”defer”和”async”,进行js文件异步加载,但是在不同浏览器会有兼容性问题。

总结

本文主要介绍了浏览器渲染过程,但是并未分析js脚本文件的解析过程,我将在下文进行分析js脚本代码是如何解析的。