浏览器渲染原理

1,311 阅读5分钟

浏览器渲染原理


浏览器解析过程会触发的事件

  • readystatechange事件

当readyState的属性值发生更改时,将触发该事件。

readyState可以取以下值:

loading:表示document仍在加载 interactive:文档已完成加载和解析,但子资源(如images,stylesheets and frames)仍在加载 complete文档和所有子资源已完成加载,load事件即将开始。

  • DOMContentLoaded事件

当最初的HTML文档已被完全加载和分析时触发,而无需等待stylesheets,images、和subframes完成加载。

DOM树渲染完成时触发DOMContentLoaded事件,此时可能外部资源还在加载。

  • load事件

当资源及其依赖的资源已完成加载时触发。当页面完全加载后(包括所有的图像、JavaScript文件、css文件等外部资源)。

load加载给定资源时将触发onload事件

DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片等
load事件触发时,页面上所有的DOM,样式表,脚本,图片都已加载完成
!! 执行顺序

readystatechange, loading状态 -> readystatechange, interactive状态 ->DOMContentLoaded事件 -> readystatechange, complete状态 -> window.onload


浏览器渲染过程

(一)HTML页面加载和解析流程 (例子)
  1. 用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件;
  2. 浏览器开始载入html代码,发现<head>标签内有一个<link>标签引用外部CSS文件;
  3. 浏览器又发出CSS文件的请求,服务器返回这个CSS文件;
  4. 浏览器继续载入html中<body>部分的代码,并且CSS文件已经拿到手了,可以开始渲染页面了;
  5. 浏览器在代码中发现一个<img>标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;
  6. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码;
  7. 浏览器发现了一个包含一行Javascript代码的<script>标签,赶快运行它;
  8. Javascript脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个<div> (style.display=”none”)。突然少了这么一个元素,浏览器不得不重新渲染这部分代码;
  9. 终于等到了</html>的到来,浏览器泪流满面……
  10. 等等,还没完,用户点了一下界面中的“换肤”按钮,Javascript让浏览器换了一下<link>标签的CSS路径;
  11. 浏览器召集了在座的各位<div><span><ul><li>们,“大伙儿收拾收拾行李,咱得重新来过……”,浏览器向服务器请求了新的CSS文件,重新渲染页面。
(二)浏览器渲染大概过程
浏览器渲染的过程主要包括以下五步:
  • 浏览器将获取的HTML文档解析成DOM树。
  • 处理CSS标记,构成层叠样式表模型CSSOM(CSS Object Model)。
  • 将DOM和CSSOM合并为渲染树(rendering tree)将会被创建,代表一系列将被渲染的对象。
  • 渲染树的每个元素包含的内容都是计算过的,它被称之为布局layout。浏览器使用一种流式处理的方法,只需要一次绘制操作就可以布局所有的元素。
  • 将渲染树的各个节点绘制到屏幕上,这一步被称为绘制painting。
(四)CSS和JS阻塞
  • css阻塞
    css是由单独的下载线程异步下载的。CSS不会阻塞DOM树的解析,但会阻塞Render的形成,也就是会阻塞也页面的渲染
CSS阻塞渲染意味着,在CSSOM完备前,页面将一直处理白屏状态,这就是为什么样式放在head中,仅仅是为了更快的解析CSS,保证更快的首次渲染。

需要注意的是,即便你没有给页面任何的样式声明,CSSOM依然会生成,默认生成的CSSOM自带浏览器默认样式。

当解析HTML的时候,会把新来的元素插入DOM树里面,同时去查找CSS,然后把对应的样式规则应用到元素上,查找样式表是按照从右到左的顺序去匹配的。

  • js阻塞
    JS会阻塞Dom树的解析,也会阻塞CSS规则树的形成
JS可以操作DOM来修改DOM结构,可以操作CSSOM来修改节点样式,这就导致了浏览器在遇到<script>标签时,DOM构建将暂停,直至脚本完成执行,然后继续构建DOM。如果脚本是外部的,会等待脚本下载完毕,再继续解析文档。现在可以在script标签上增加属性defer或者async。脚本解析会将脚本中改变DOM和CSS的地方分别解析出来,追加到DOM树和CSSOM规则树上。

每次去执行JavaScript脚本都会严重地阻塞DOM树的构建,如果JavaScript脚本还操作了CSSOM,而正好这个CSSOM还没有下载和构建,浏览器甚至会延迟脚本执行和构建DOM,直至完成其CSSOM的下载和构建。所以,script标签的位置很重要。

(三)defer&async
1.<script src="script.js"></script>
没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。

2.<script async src="script.js"></script>

有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。

3.<script defer src="myscript.js"></script>

有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。

img
蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。

参考:www.jianshu.com/p/e6252dc9b…