浏览器渲染流程

一、浏览器渲染的过程简析

关键渲染路径 (Critical Rendering Path)是指与当前用户操作有关的内容。例如用户在浏览器中打开一个页面,其中页面所显示的东西就是当前用户操作相关的内容,也就是浏览器从服务器那收到的HTML,CSS,JavaScript等相关资源,然后经过一系列处理后渲染出来web页面。实际抽象出来理解可以将这些步骤看作一个函数,就输入HTML,经过一层层的处理,最后输出像素。

而浏览器渲染的过程主要包括以下几步:

浏览器将获取的HTML文档并解析成DOM树。

将 css 文件处理成 StyleSheet 对象,从而进行样式计算。

根据dom树和StyleSheet 生成布局树。

根据具体的节点信息对页面进行分层处理,生成图层树

根据图层树生成绘制列表

合成线程通过主线程提交的绘制列表对图层进行分块,并进行栅格化,生成位图

合成位图,并将其显示

具体如下图过程如下图所示:

浏览器渲染流程_第1张图片

需要注意的是,以上几个步骤并不一定是一次性顺序完成,比如 DOM 被修改时,亦或是哪个过程会重复执行,这样才能计算出哪些像素需要在屏幕上进行重新渲染。而在实际情况中,JavaScript和CSS的某些操作往往会多次修改DOM或者CSSOM。

值得注意的的是,在每个阶段,都会有对应的输入,处理,以及输出。下面我们就来详细的了解一下这几个过程及需要注意的事项。

二、浏览器渲染网页的具体流程

2.1 构建DOM树

因为浏览器无法直接使用HTML/SVG/XHTML,因此当浏览器客户端从服务器那接受到HTML文档后,就会遍历文档节点,然后对这些文档节点通过HTML解析器进行解析,最后生成DOM树,所生成的 DOM 树结构和HTML标签一一对应。需要注意的是,在这其中HTML解析器会进行诸如:标记化算法,树构建算法等操作,其中的规范即遵循了W3C的相应规范,也都有浏览器引擎自己的一些特定的操作,详情可以翻阅这篇非常著名的文章:

How Browsers Work: Behind the scenes of modern web browsers

在此阶段,输入的即是一个HTML文件,然后会有浏览器的HTML解析器对其进行解析,输出树形结构的DOM树。值得注意的是,HTML解析器并不是等整个文档全部加载完之后才开始解析的,而是网络进程加载了多少数据,HTML解析器就会解析多少数据。相当与在网络进程与渲染进程之间会在这期间建立一个数据共享的管道,网络进程每次收到数据都会将其转发到渲染进程,从而保证渲染进程中的HTML解析器可以源源不断的获取到用于渲染的数据。这个过程可以理解为下方这个过程:

将字节流通过分词器转化为 Token

根据 Token 生成节点 node

根据生成的节点,组成 DOM 树

每个页面的DOM树,我们也可以直接通过在控制台输入document 来进行访问。

对于DOM树,我们需要注意以下几点:

DOM 树从内容上来看和 HTML 几乎一模一样,但 DOM 是保存在内存中的树形结构,可以通过 JavaScript 来查询和修改。

document.getElementsByTagName("h2")[0].innerText = "Hello World"

display:none 的元素也会在 DOM 树中。

注释也会在 DOM 树中

script 标签会在 DOM 树中

DOM 树在构建的过程中可能会被 CSS 和 JS 的加载而执行阻塞。

此外DOM 树在构建的过程中可能会被 CSS 和 JS 的加载而执行阻塞,也就是我们常说的阻塞渲染。这是因为HTML文件是通过HTML解析器转化成 DOM 树的,而在HTML解析器中如果遇到了 JavaScript 脚本,HTML 解析器会先执行 JavaScript 脚本,待这个脚本执行完成之后,再继续往下解析。因此我们常说,将script标签放在body下面,通常就是基于这种考虑的。但为什么CSS也有可能会阻塞DOM树的构建呢,可以看下面一个栗子: