浏览器是咱们平常开发的重要的工具,那么你了解浏览器吗?即便在前端面试中,咱们也常常会遇到:在浏览器地址中从输入url地址到出现页面,这个过程发生了什么?介绍一下重绘和回流?这一类关于浏览器的问题。咱们可能会知道大概的轮廓但对于具体的细节倒是不那么清楚,那么今天咱们就从浏览器组成开始来了解一下浏览器的渲染机制javascript
浏览器主要由7个部分组成:css
浏览器内核分为两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎html
常见的浏览器内核:Trident(IE)、Gecko(火狐)、Blink(Chrome、Opera)、Webkit(Safari)前端
在了解浏览器渲染过程以前,先来了解一下页面的加载流程。有助于更好理解后续渲染过程。从浏览器地址中从输入url地址到渲染出一个页面,会通过如下过程。 1.浏览器输入的url地址通过DNS解析得到对应的IP 2.向服务器发起TCP的3次握手 3.创建连接后,浏览器向该IP地址发送http请求 4.服务器接收到请求,返回一堆 HMTL 格式的字符串代码 5.浏览器得到html代码,解析成DOM树 6.获取CSS并构建CSSOM 7.将DOM与CSSOM结合,建立渲染树 8.找到全部内容都处于网页的哪一个位置,布局渲染树 9.最终绘制出页面java
咱们将要介绍的浏览器渲染过程主要步骤是5-9步,能够用下面的图来形象的展现 面试
这个解析过程大概能够分为几个步骤: segmentfault
注意:带有结束标签标识的Token不会建立节点对象 第四步:经过“开始标签”与“结束标签”来识别并关联节点之间的关系。当全部Token都生成并消耗完毕后,咱们就获得了一颗完整的DOM树。后端
可是如今有一个疑问,节点之间的关联关系是如何维护的呢? 上面咱们提到Token会标识是“开始标签”仍是“结束标签”,如下图为例:“Hello”Token位于“title”开始标签与“title”结束标签之间,代表“Hello”Token是“title”Token的子节点。同理“title”Token是“head”Token的子节点。 浏览器
既然有了html解析,那css解析也是必不可少的,解析css构建CSSOM 的过程和构建DOM的过程很是的类似。当浏览器接收到一段CSS,浏览器首先要作的是识别出Token,而后构建节点并生成CSSOM 缓存
CSS匹配HTML元素是一个至关复杂和有性能问题的事情。因此,DOM树要小,CSS尽可能用id和class,千万不要过渡层叠下去 因此,CSS的加载速度与构建CSSOM的速度将直接影响首屏渲染速度,所以在默认状况下CSS被视为阻塞渲染的资源
当咱们生成DOM树和CSSOM树后,咱们须要将这两颗树合并成渲染树,在构建渲染树的过程当中浏览器须要作以下工做:
在渲染的过程当中,遇到一个script标记时,就会中止渲染,去请求脚本文件并执行脚本文件,由于浏览器渲染和 JS 执行共用一个线程,并且这里必须是单线程操做,多线程会产生渲染 DOM 冲突。JavaScript的加载、解析与执行会严重阻塞DOM的构建。只有等到脚本文件执行完毕,才会去继续构建DOM。
js不单会阻塞DOM构建,还会致使CSSOM也阻塞DOM的构建,若是JavaScript脚本还操做了CSSOM,而正好这个CSSOM尚未下载和构建,浏览器甚至会延迟脚本执行和构建DOM,直至完成其CSSOM的下载和构建,而后再执行JavaScript,最后在继续构建DOM
所以script的位置很重要,在实际使用过程当中遵循如下两个原则:
浏览器拿到渲染树后,就会从渲染树的根节点开始遍历,而后肯定每一个节点对象在页面上的确切大小与位置,一般这一行为也被称为“自动重排”。布局阶段的输出是一个盒子模型,它会精确地捕获每一个元素在屏幕内的确切位置与大小,全部相对测量值都将转换为屏幕上的绝对像素。这一过程也可称为回流
布局完成后,浏览器会当即发出“Paint Setup”和“Paint”事件,将渲染树转换成屏幕上的像素。
在咱们了解浏览器的渲染机制后,DOM 和 CSSOM 结构构建顺序,咱们能够针对性能优化问题给出一些方案,提高页面性能。
当元素的样式发生变化时,浏览器须要触发更新,从新绘制元素。这个过程当中,有两种类型的操做,即重绘与回流。
注意:回流必定会触发重绘,而重绘不必定会回流,重绘的开销较小,回流的代价较高
所以为了减小性能优化,咱们能够尽可能避免回流或者重绘操做 css
javascript
defer 和 async 属性的区别:
2)状况2 (异步下载) async 属性表示异步执行引入的 JavaScript,与 defer 的区别在于,若是已经加载好,就会开始执行——不管此刻是 HTML 解析阶段仍是 DOMContentLoaded 触发以后。须要注意的是,这种方式加载的 JavaScript 依然会阻塞 load 事件。换句话说,async-script 可能在 DOMContentLoaded 触发以前或以后执行,但必定在 load 触发以前执行。
3)状况3 <scriptdefersrc="script.js">(延迟执行) defer 属性表示延迟执行引入的 JavaScript,即这段 JavaScript 加载时 HTML 并未中止解析,这两个过程是并行的。整个 document 解析完毕且 defer-script 也加载完成以后(这两件事情的顺序无关),会执行全部由 defer-script 加载的 JavaScript 代码,而后触发 DOMContentLoaded 事件。
defer 与相比普通 script,有两点区别:
js优化能够在script标签加上 defer属性 和 async属性用于在不阻塞页面文档解析的前提下,控制脚本的下载和执行
其余: CSS 标签的 rel属性 中的属性值设置为 preload 可以让你在你的HTML页面中能够指明哪些资源是在页面加载完成后即刻须要的,最优的配置加载顺序,提升渲染性能
咱们已经将浏览器的渲染机制了解了一遍,不只了解到一些性能优化方案,也能够得出结论: 浏览器渲染的关键路径共分五个步骤:
构建DOM -> 构建CSSOM -> 构建渲染树 -> 布局 -> 绘制
参考连接