从输入url到页面渲染完成经历的那些事~

网络部分

1. DNS域名解析

第一个过程:将域名解析为对应的IP地址。

查找流程:浏览器缓存 -> 系统缓存 -> 系统hosts文件 -> 路由器缓存 -> 本地DNS服务器 -> 其它服务器

一旦找向其它服务器,则进入递归查找过程:顶级域名服务器 -> 二级域名服务器 -> 三级域名服务器 -> ...

2. 建立TCP连接

一旦找到了对应的服务器,则客户端与服务器通过TCP三次握手建立连接,以便传输数据。

  • 客户端 -> 服务器:你好,我想跟你连接可以吗?(SYN=1,seq=x)
  • 服务器 -> 客户端:可以,你确定要连接是吧?(SYN=1,ACK=1,seq=y,ack=x+1)
  • 客户端 -> 服务器:确定,我们连接吧!(ACK=1,seq=x+1,ack=y+1)

3. HTTP请求与响应

一旦建立了TCP连接,客户端与服务器之间就可以来传递数据了:由客户端发起HTTP请求,服务器端给到HTTP响应。

4. 断开TCP连接

传输数据完成后,通过四次挥手断开TCP连接:

  • 客户端 -> 服务器:好了,咱们断开吧(FIN=1,seq=u)
  • 服务器 -> 客户端:行,等我稍微检查一下还有没有要发你的数据(ACK=1,seq=v,ack=u+1)
  • 服务器 -> 客户端:可以了,咱们断开吧,拜拜(FIN=1,ACK=1,seq=w,ack=u+1)
  • 客户端 -> 服务器:好的,再会,拜拜(ACK=1,seq=u+1,ack=w+1)

浏览器部分

1. 浏览器解析文件

  • 解析HTML生成DOM树
  • 解析CSS生成CSSOM树
  • 解析JS

2. 构建render渲染树

根据CSSOM和DOM生成渲染树,渲染树中不包含display为none的元素

3. 绘制渲染树

  • 浏览器会对这些元素进行定位和布局,这一步也叫做reflow或者layout。
  • 浏览器绘制这些元素的样式,颜色,背景,大小及边框等,这一步也叫做repaint。
  • 在绘制阶段,浏览器会遍历渲染树,调用渲染器的paint()方法在屏幕上显示其内容。

 细节问题:

1. reflow回流与repaint重绘

参考链接:https://www.jianshu.com/p/b6b42fd3f80e

  • reflow(回流):当浏览器发现某个部分发生了变化从而影响了布局,这个时候就需要倒回去重新渲染,大家称这个回退的过程叫 reflow。 常见的reflow是一些会影响页面布局的操作,诸如Tab,隐藏等。reflow 会从 html 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置,以确认是渲染树的一部分发生变化还是整个渲染树。reflow几乎是无法避免的,因为只要用户进行交互操作,就势必会发生页面的一部分的重新渲染,且通常我们也无法预估浏览器到底会reflow哪一部分的代码,因为他们会相互影响。
  • repaint(重绘): repaint则是当我们改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸和位置没有发生改变。

需要注意的是,display:none 会触发 reflow,而visibility: hidden属性则并不算是不可见属性,它的语义是隐藏元素,但元素仍然占据着布局空间,它会被渲染成一个空框,这在我们上面有提到过。所以visibility:hidden 只会触发 repaint,因为没有发生位置变化。

2. 浏览器渲染的细节问题

参考链接:https://www.cnblogs.com/caizhenbo/p/6679478.html

                  https://www.cnblogs.com/zhmhhu/p/6250060.html

浏览器渲染原理:

当我们在浏览器地址输入URL时,浏览器会发送请求到服务器,服务器将请求的HTML文档发送回浏览器,浏览器将文档下载下来后,便开始从上到下解析,解析完成之后,会生成DOM。如果页面中有css,会根据css的内容形成CSSOM,然后DOM和CSSOM会生成一个渲染树,最后浏览器会根据渲染树的内容计算出各个节点在页面中的确切大小和位置,并将其绘制在浏览器上。浏览器遇到HTML文档中的<script>元素以及CSS样式文件(并且没有async或defer属性),就暂停解析,开始执行脚本和CSS样式。

为什么一再强调将css放在头部,将js文件放在尾部:

在面试的过程中,经常会有人在回答页面的优化中提到将js放到body标签底部,原因是因为浏览器生成Dom树的时候是一行一行读HTML代码的,script标签放在最后面就不会影响前面的页面的渲染。那么问题来了,既然Dom树完全生成好后页面才能渲染出来,浏览器又必须读完全部HTML才能生成完整的Dom树,script标签不放在body底部是不是也一样,因为dom树的生成需要整个文档解析完毕。

其实现代浏览器为了更好的用户体验,渲染引擎将尝试尽快在屏幕上显示的内容。它不会等到所有HTML解析之前开始构建和布局渲染树。部分的内容将被解析并显示。也就是说浏览器能够渲染不完整的dom树和cssom,尽快的减少白屏的时间。假如我们将js放在header,js将阻塞解析dom,dom的内容会影响到First Paint,导致First Paint延后。所以说我们会将js放在后面,以减少First Paint的时间,但是不会减少DOMContentLoaded被触发的时间。

补充:First Paint渲染的是在遇到第一个js脚本时,已构建好的部分渲染树。

参考:https://www.cnblogs.com/hongrunhui/p/8929001.html

关于JS阻塞DOM解析:

当解析过程中遇到<script>标签的时候,便会停止解析过程,转而去处理脚本,如果脚本是内联的,浏览器会先去执行这段内联的脚本,如果是外链的,那么先会去加载脚本,然后执行。在处理完脚本之后,浏览器便继续解析HTML文档。

同时javascript的执行会受到标签前面样式文件的影响。如果在标签前面有样式文件,需要样式文件加载并解析完毕后才执行脚本。这是因为javascript可以查询对象的样式。

这里需要注意一点,在现在浏览器中,为了减缓渲染被阻塞的情况,现代的浏览器都使用了猜测预加载。当解析被阻塞的时候,浏览器会有一个轻量级的HTML(或CSS)扫描器(scanner)继续在文档中扫描,查找那些将来可能能够用到的资源文件的url,在渲染器使用它们之前将其下载下来。

DOMContentLoaded与Load事件

DOMContentLoaded是指dom内容加载完毕,当文档中没有脚本时,浏览器解析完文档便能触发 DOMContentLoaded 事件;如果文档中包含脚本,则脚本会阻塞文档的解析,而脚本需要等位于脚本前面的css加载完才能执行。在任何情况下,DOMContentLoaded 的触发不需要等待图片等其他资源加载完成。

接下来,我们来说说load,页面上所有的资源(图片,音频,视频等)被加载以后才会触发load事件,简单来说,页面的load事件会在DOMContentLoaded被触发之后才触发。

我们在 jQuery 中经常使用的 $(document).ready(function() { // ...代码... }); 其实监听的就是 DOMContentLoaded 事件,而 $(document).load(function() { // ...代码... }); 监听的是 load 事件。在用jquery的时候,我们一般都会将函数调用写在ready方法内,就是页面被解析后,我们就可以访问整个页面的所有dom元素,可以缩短页面的可交互时间,提高整个页面的体验。

总结:ready(DOMContentLoaded)表示文档结构已经加载完成(不包含图片等非文字媒体文件);load表示页面包含图片等外部文件在内的所有元素都加载完成。

3. 优化浏览器渲染效率的建议

  • 合法地去书写 HTML 和 CSS ,且不要忘了文档编码类型。
  • 样式文件应当在 head 标签中,而脚本文件在 body 结束前,这样可以防止阻塞firstpaint。
  • 简化并优化CSS选择器,尽量将嵌套层减少到最小。
  • 尽量减少在 JavaScript 中进行DOM操作。
  • 修改元素样式时,更改其class属性是性能最高的方法。
  • 尽量用 transform 来做形变和位移
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值