浏览器解析URL的过程
一、基本过程
1、概念:浏览器的内核分为两个核心部分,渲染引擎与js引擎,拿Chrome来说,它的渲染引擎是webkit渲染引擎,js引擎为v8。渲染引擎用来渲染窗口,可以显示html,xml,xhtml,图片等,也可以通过插件渲染其他的文件。例如PDF,在此不做讨论。
2、请求过程
在浏览器地址栏输入url地址,按下回车键
浏览器获取url进行域名解析,首先从本地DNS缓存查找,如果本地没有则去DNS服务器查找,如果都没有找到,则浏览器返回请求失败
DNS解析出请求地址,浏览器想这个地址发送请求
进行tcp三次握手建立连接
tcp/ip连接建立后,浏览器向服务器发送http请求,服务处理请求并返回相应的资源(如果有缓存就在缓存中去)
客户端下载资源,浏览器将内容展示到窗口
3、渲染过程
渲染引擎解析html生成DOM Tree,此时display:none的元素也存在与DOM Tree
渲染引擎解析css生成CSS Rule Tree(css规则树)
通过js引擎来解析Javascript脚本,主要是通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree.
DOM Tree 与CSS Rule Tree结合生成Render Tree(渲染树),这时display:none的元素已不存在与render tree中
然后计算每个DOM节点的位置大小等,根据渲染树来布局,这一过程叫reflow(回流)
最后调用系统Native GUI API进行绘制(重绘)
4、渲染过程遇到js文件怎么处理?
JavaScript的加载、解析与执行会阻塞DOM的构建,也就是说,在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建。
也就是说,如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这也是都建议将 script 标签放在 body 标签底部的原因。当然在当下,并不是说 script 标签必须放在底部,因为你可以给 script 标签添加 defer 或者 async 属性(下文会介绍这两者的区别)。
JS文件不只是阻塞DOM的构建,它会导致CSSOM也阻塞DOM的构建。
原本DOM和CSSOM的构建是互不影响,井水不犯河水,但是一旦引入了JavaScript,CSSOM也开始阻塞DOM的构建,只有CSSOM构建完毕后,DOM再恢复DOM构建。
这是什么情况?
这是因为JavaScript不只是可以改DOM,它还可以更改样式,也就是它可以更改CSSOM。前面我们介绍,不完整的CSSOM是无法使用的,但JavaScript中想访问CSSOM并更改它,那么在执行JavaScript时,必须要能拿到完整的CSSOM。所以就导致了一个现象,如果浏览器尚未完成CSSOM的下载和构建,而我们却想在此时运行脚本,那么浏览器将延迟脚本执行和DOM构建,直至其完成CSSOM的下载和构建。也就是说,在这种情况下,浏览器会先下载和构建CSSOM,然后再执行JavaScript,最后在继续构建DOM。
5、回流与重绘
回流:当render tree中的一部分(或全部)因为元素的规模尺寸、布局、隐藏等改变而需要重新构建
重绘:当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观、风格,而不会影响布局的,比如background-color
回流必定会发生重绘,重绘不一定会引发回流。重绘和回流会在我们设置节点样式时频繁出现,同时也会很大程度上影响性能。回流所需的成本比重绘高的多,改变父节点里的子节点很可能会导致父节点的一系列回流。
6、常见引起回流的属性和方法
添加或者删除可见的DOM元素;
元素尺寸改变——边距、填充、边框、宽度和高度
内容变化,比如用户在input框中输入文字
浏览器窗口尺寸改变——resize事件发生时
计算 offsetWidth 和 offsetHeight 属性
设置 style 属性的值
7、如何减少回流和重绘
使用 transform 替代 top
使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)
不要把节点的属性值放在一个循环里当成循环里的变量
不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局
动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame
CSS 选择符从右往左匹配查找,避免节点层级过多
将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点。比如对于 video 标签来说,浏览器会自动将该节点变为图层
8、为什么操作DOM慢
因为 DOM 是属于渲染引擎中的东西,而 JS 又是 JS 引擎中的东西。当我们通过 JS 操作 DOM 的时候,其实这个操作涉及到了两个线程之间的通信,那么势必会带来一些性能上的损耗。操作 DOM 次数一多,也就等同于一直在进行线程之间的通信,并且操作 DOM 可能还会带来重绘回流的情况,所以也就导致了性能上的问题。
9、渲染问题
FOUC:由于浏览器渲染机制(比如firefox),再CSS加载之前,先呈现了HTML,就会导致展示出无样式内容,然后样式突然呈现的现象;
白屏:有些浏览器渲染机制(比如chrome)要先构建DOM树和CSSOM树,构建完成后再进行渲染,如果CSS部分放在HTML尾部,由于CSS未加载完成,浏览器迟迟未渲染,从而导致白屏;也可能是把js文件放在头部,脚本会阻塞后面内容的呈现,脚本会阻塞其后组件的下载,出现白屏问题。
10、defer与async
11、结论
浏览器工作流程:构建DOM -> 构建CSSOM -> 构建渲染树 -> 布局 -> 绘制。
CSSOM会阻塞渲染,只有当CSSOM构建完毕后才会进入下一个阶段构建渲染树。
通常情况下DOM和CSSOM是并行构建的,但是当浏览器遇到一个script标签时,DOM构建将暂停,直至脚本完成执行。但由于JavaScript可以修改CSSOM,所以需要等CSSOM构建完毕后再执行JS。
如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件,建议将 script 标签放在 body 标签底部。
二、性能优化
1,提升HTML加载速度
- 页面精简,删除不必要的注释,空格,将内嵌的JS和CSS移至外部文件,使用压缩工具等。
- 减少文件数量,减少页面上引入的文件数量可以减少请求的次数,可以合并的JS和CSS文件尽量合并。
- 减少域名查询,DNS查询和解析域名需要消耗时间,减少对外部JavaScript、CSS、图片等资源的引用,不同域名的使用越少越好。
- 使用缓存,重用数据。
- 优化页面元素的加载顺序。
- 使用现在CSS和合法的标签。
- 指定图片的大小,如果浏览可以立即确定图片大小就不需要重新进行布局操作。
- 根据浏览器类型选择合适的策略。
- 使用压缩工具等。
- 页面精简,删除不必要的注释,空格,将内嵌的JS和CSS移至外部文件,使用压缩工具等。
2,编写合理的CSS
首先说明CSS选择符的匹配顺序,从右到左!从右到左!从右到左!(重要的事情说三遍),所以,类似于“#nav li” 我们以为很简单的规则,应该马上就可以匹配成功,但是,需要从右往左匹配,所以,先会去查找所有的li,然后再去确定它的父元素是不是#nav。因此,编写合理的CSS也可以提高我们的页面行能:
- DOM的深度尽量浅,不要嵌套过深。
- 减少inline javascript css的数量。
- 使用合法的CSS属性。
- 不要为ID选择器指定类名或者标签名。
- 避免后代选择器,尽量使用子选择器。
- 避免使用通配符。
3,关于javascript标签
对于javascript标签首先得了解其加载和执行的特点:1,载入后立即执行,2,执行时会阻塞页面后续的内容,针对这些特点,我们使用javascript标签时应该注意:
- 将所有的javascript标签放在页面底部,也就是body标签闭合之前,这样可以保证脚本执行前已完成DOM渲染。
- 尽可能合并脚本,页面中引入的脚本越少,加载响应速度也就越快。
- 减少inline javascript的使用。
- 所有的javascript标签会按照其引入顺序依次执行,只有前面的内容解析完成才会解析下一个,所以注意多个javascript标签的引入顺序。
- 使用defer属性,该属性可以使脚本在文档完全呈现以后再执行。
- 使用async属性,可以使当前脚本不必等待其他脚本的执行,也不必阻塞文档的呈现。
三、 结语
关于浏览器渲染的内容基本就是这些了,下面引用网上一篇比较好相关文章中的一段做个总结:
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文件,重新渲染页面
如果需要了解更多详细的内容,请参阅下面的资料。
参考资料:
1,权威资料:how browsers work(英文,特别长,但是很权威);
2,如果看英文有困难的可以看看下面的翻译版本——浏览器工作原理简介。