浏览器渲染页面的过程

1. 主要过程

下图是浏览器解析一个页面的主要过程,大体上为:下载HTML - 并行下载 head 中的 CSS JS - 生成 DOM 数、CSSOM 树 - 生成渲染树 - DOMContentLoaded 事件被触发 - 加载其他资源 - window.onload 事件被触发

更简化一点:下载资源 - 渲染解析 - 展示页面

加载页面的过程

但是在展示页面时,所有的操作并非是一个线性的过程,其中还有很多并行操作与阻塞操作,整理一下具体的过程可以为:

首先,开源浏览器一般以8k每块下载html页面。然后解析页面生成DOM树,遇到css标签或JS脚本标签就新起线程去下载他们,并继续构建DOM。下载完后解析CSS为CSS规则树,浏览器结合CSS规则树和DOM树生成Render Tree。

注意:构建 CSS Object Model(CSSOM)会阻塞 JavaScript 的执行。JavaScript 的执行也会阻塞 DOM 的构建。

JavaScript下载后可以通过DOM API修改DOM,通过 CSSOM API 修改样式作用域 Render Tree。

每次修改会造成Render Tree的重新布局和重绘。只要修改DOM或修改了元素的形状或大小,就会触发Reflow,单纯修改元素的颜色只需Repaint一下(调用操作系统Native GUI的API绘制)。

2. 资源的下载过程

对于一个完整的网站,首先会下载页面的 HTML,当 HTML 下载完成后,就开始进行 HTML 解析,在解析的过程中,遇到需要下载的外部 css 或者 js 会对其进行异步下载,但是当页面遇到了 JS 时,解析会被阻塞,需要先执行 JS 脚本,再解析后面的内容。

但是在现代浏览器中,为了防止 JS 解析消耗过长的时间,浏览器在 HTML 下载完成后会预览整个 HTML 的 dom 结构,不论当前 DOM 解析引擎是否进行到加载资源的位置,都会统一预下载页面中所有的资源,所以资源的下载不会是一个阻塞的过程,资源会按照先后顺序进行下载。

如下图,我们在 HTML head 标签引入的 JS 脚本执行需要 10s ,浏览器并不会等待 10s ,而是直接先去下载后面的资源:

这里要提一点的是,由于 JS 和 CSS 是页面渲染的重要资源,而图片、媒体资源并非是重要资源,所以图片、媒体资源并不影响页面的渲染,他们只会影响页面 onload 的触发时间。

3. 解析渲染的过程

浏览器在下载页面资源的同时,开始对页面进行解析与渲染,这是两个分离的过程。解析是生成 DOM 结构,JS 可以操作已被解析的 DOM;而渲染是将 DOM 与 CSSOM 相结合生成渲染数显示到界面的过程,渲染了之后用户才可以在屏幕上看到图像。

在解析渲染的过程中,我们要明晰三点:

  • JS 加载会阻塞页面的解析与渲染
  • CSS 加载不会阻塞页面解析,但是会阻塞页面渲染
  • CSS 会阻塞 JS 的执行

首先 JS 会阻塞页面的解析与渲染,实际上 JS 阻塞的是 DOM 的解析过程,既然无法完成解析,就无法进行渲染了。

DOM 解析到 JS 标签处,如果没有下载完,先渲染出前面的部分,等待 JS 的下载与执行;

20191129215321.png

DOM 解析到 JS 标签出,如果下载完了,等待 JS 执行完毕后再渲染页面。

20191129215127.png